• iOS进阶第三节 数据处理之CoreData


    一、CoreData数据库框架的优势

      1>. CoreData历史

    • CoreData数据持久化框架是Cocoa API的一部分,首次在iOS5版本的系统中出现,它允许按照 实体 - 属性 - 值 模型组织数据,并以XML、二进制文件或者SQLite数据文件的格式持久化数据
    • CoreData主要提供 对象 - 关系映射(ORM)功能,把OC对象转化为数据保存到文件,也可以数据转化为OC对象。

      2>. CoreData数据库框架的优势

      sqlite:①. 基于C接口,需要使用SQL语句,代码繁琐

           ②. 在处理大量数据时,表关系更直接

           ③. 在OC中不是可视化的

      CoreData:①. 可视化,有undo/redo能力

             ②. 可以实现多种文件格式NSSQLiteStoreType、

              NSBinaryStoreType、NSInMemoryStoreType、NSXMLStoreType 

             ③. 苹果官方API支持,与iOS结合更紧密 

      3>. CoreData核心对象

      实体管理类:NSManagedObject

      实体描述类:NSEntityDescription

      实体管理器类:NSManagedObjectContext

      实体连接类:NSPersistenStoreCoordinator

      数据模型器类:NSManagedObjectModel

      4>. CoreData核心类关系

    二、CoreData数据库框架的核心对象

      1>. 持久化存储和存储文件

    • NSPersistentStore:持久化存储,是对实际文件的一种Object-C表示方式,一个被封装好的底层类,用于存储数据
    • 存储文件:用来存储和管理数据的文件,iOS支持4种存储类型:NSSQLiteStoreType、NSBinaryStoreType、NSInMemoryType、NSXMLStoreType

      2>. 被管理对象上下文

    • NSManagedObjectContext:被管理对象上下文CoreData中用于操作和使用数据,负责应用和数据库之间的交互
    • 数据的保存需要NSManagedObjectContext进行sava操作
    • 数据的查询需要NSManagedObjectContext进行executeFetchRequest操作(返回值是数组)
    • CoreData提供的是对象关系映射,NSManagedObjectContext操作的都是NSManagedObject对象

      3>. 被管理对象相关类

    • NSManagedObjectMode:被管理对象模型,管理多个对象
    • NSmanagedObject:被管理对象,CoreData返回的数据模型,被管理的对象是根据实体描述生成的
    • NSEntityDescription:实体描述类,根据实体创建被管理对象
    • Entity:实体类,实体是对文件数据的描述。被管理对象表示实体,实体包含名称,属性(字段)和关系,实体的名称通常和被管理对象一致

      4>. 数据查询类

    • NSFetchRequest:查询请求,可以做拍讯操作,也可以使用谓词
    • NSManagedObjectContext根据NSFetchRequest查询数据,以数组形式返回,数组中包含被管理对象(NSManagedObject)
    • NSSortDescriptor:排序操作

     

    三、CoreData数据库的简单操作

      1>. 创建实体类与属性

    • 在创建工程时选上 Use Core Data ,在工程中会多出一个 CoreData.xcdatamodeld 文件,点击它,在右边点击的左下角的 Add Entity 的加号按钮创建实体类。
    • 点击创建的实体类,左边会有三组添加选项,其中第一组 Attributes 就是为实体类添加属性,第二组 Relationships 是为实体类添加表关系,在左下方点击Style就可以切换可视化关系图
    • 点击实体类,在系统工具上方的Editor中可选项Create NSmanagedObject Subclass,选择对应的CoreData、实体类,就可以出创建相应的实体类文件,文件中已经有你添加好的属性。

      2>. 使用 Use Core Data 时系统已经声明的属性和实现的方法

    #import <UIKit/UIKit.h>
    #import <CoreData/CoreData.h>
    
    @interface AppDelegate : UIResponder <UIApplicationDelegate>
    
    @property (strong, nonatomic) UIWindow *window;
    
    @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; // 数据管理器类,临时数据库
    @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; // 数据模型器类,包含多个实体,实体中设置的属性,
      实体名称等,可以认为是一个实体集合,相当于数据库中的表 @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; // 数据连接器类,
      连接磁盘与内存中的临时数据库 - (void)saveContext; - (NSURL *)applicationDocumentsDirectory; @end

       具体的实现方法

    #pragma mark - Core Data stack

    @synthesize managedObjectContext = _managedObjectContext;
    @synthesize managedObjectModel = _managedObjectModel;
    @synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

    // 这个方法的作用是获取Documents的路径,只不过这里的返回值是NSURl,而我们之前获取的路径是NSString,这个返回值在coreDate其他方法中当参数
    - (NSURL *)applicationDocumentsDirectory {
        // The directory the application uses to store the Core Data store file. This code uses a directory named "lanou3g.CoreData" in the application's documents directory.
        return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    }

    // 需要用到此对象时才去加载,不需要时不加载,提高性能,增强对内存的有效使用
    - (NSManagedObjectModel *)managedObjectModel {
        // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
        if (_managedObjectModel != nil) {
            return _managedObjectModel;
        }
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreData" withExtension:@"momd"];
        // 获取文件编译后的文件路径,数据模型器与CoreData.xcdatamodeld密切相关,CoreData.xcdatamodeld编译后形成的文件后缀名就是momd。
        
        _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        // 从得到的路径中加载数据模型器对象

        return _managedObjectModel;
    }

    // 持久存储助理,数据连接器类
    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
        // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
        if (_persistentStoreCoordinator != nil) {
            return _persistentStoreCoordinator;
        }
        
        // Create the coordinator and store
        
        _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
        // 创建数据连接器对象,需要数据模型器作为参数,应为数据模型器决定了连接器从数据库文件中取得数据
        
        NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreData.sqlite"];
        // 找到磁盘中数据库存放的路径,连接操作需要知道源路径

        NSError *error = nil;
        NSString *failureReason = @"There was an error creating or loading the application's saved data.";
        
        NSDictionary *dic = @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES}; // 支持版本迁移,支持数据迁移。
        
        if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:dic error:&error]) { //options参数是一个字典,这个字典保存的是coreData的默认设置,比如是否允许数据迁移,默认是不允许的,如果想要完成数据迁移,后期需要系应该这个参数
            // Report any error we got.
            
            // 下面创建的字典,就是保存错误信息的,如果数据连接器类连接失败,就会相应的将错误信息从字典中取出,打印出来
            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
            dict[NSLocalizedFailureReasonErrorKey] = failureReason;
            dict[NSUnderlyingErrorKey] = error;
            error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
            // Replace this with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort(); // 终止程序
        }
        
        return _persistentStoreCoordinator;
    }

    // 数据管理器类
    - (NSManagedObjectContext *)managedObjectContext {
        // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
        if (_managedObjectContext != nil) {
            return _managedObjectContext;
        }
        
        // 每一个数据管理器对象,都需要一个数据连接器
        NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
        if (!coordinator) {
            return nil;
        }
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
        return _managedObjectContext;
    }

    #pragma mark - Core Data Saving support

    - (void)saveContext {
        NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
        if (managedObjectContext != nil) {
            NSError *error = nil;
            if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
                // 临时数据库(数据管理器类)对文件进行操作后,同步保存回磁盘时失败,那么此时打印失败信息,终止程序
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        }
    }

      3>. 使用CoreData实现增删改查

    // 封装一个插入学生的方法
    - (void)insertStudentWithName:(NSString *)name gender:(NSString *)gender age:(NSNumber *)age {
        // 1、增加数据,插入数据
        /*
         NSManagedObjectModel *managedObjectModel =
         [[context persistentStoreCoordinator] managedObjectModel];
         
         NSEntityDescription *entity =
         [[managedObjectModel entitiesByName] objectForKey:entityName];
         
         NSManagedObject *newObject = [[NSManagedObject alloc]
         initWithEntity:entity insertIntoManagedObjectContext:context];
         
         return newObject;
         */
        Student *stu = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.managedObjectContext]; 
      // 在临时数据库中,按照实体Student,加载出一个视图管理对象(数据模型) // 模型赋值有两种:KVC,属性点语法 stu.name = name; [stu setValue:gender forKey:@"gender"]; stu.age = age; // 数据管理类执行同步操作,将数据写入数据库 [self.managedObjectContext save:nil]; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. // coreData完成增删改查 // 1、增加数据,插入数据 // 创建模型 // [self insertStudentWithName:@"巴达" gender:@"雄" age:@20]; // [self insertStudentWithName:@"大宝" gender:@"女" age:@10]; // [self insertStudentWithName:@"秋香" gender:@"雌" age:@18]; // 2、查询数据 // 创建查询请求对象 // NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Student"]; // 这样的数据请求对象得到的是数据库中的所有记录 // // // 让数据管理对象执行请求 // NSArray *array =[self.managedObjectContext executeFetchRequest:request error:nil]; // for (Student *stu in array) { // NSLog(@"name is %@, gender is %@, age is %@", stu.name, stu.gender, stu.age); // } // 为了更加方便的完成查询操作,查询请求可以添加谓词和排序 NSFetchRequest *request = [[NSFetchRequest alloc] init]; // 得到一个实体描述 NSEntityDescription *entity = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:self.managedObjectContext]; request.entity = entity; // 添加谓词 // NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@ or gender = %@", @"*香*", @"女"]; // request.predicate = predicate; // NSArray *array = [self.managedObjectContext executeFetchRequest:request error:nil]; // for (Student *stu in array) { // NSLog(@"name is %@, gender is %@, age is %@", stu.name, stu.gender, stu.age); // } // 添加排序 // NSSortDescriptor *descripor = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES]; // 创建按照年龄升序排列的排序条件 // request.sortDescriptors =@[descripor]; // NSArray *array = [self.managedObjectContext executeFetchRequest:request error:nil]; // for (Student *stu in array) { // NSLog(@"name is %@, gender is %@, age is %@", stu.name, stu.gender, stu.age); // } // 3、修改数据 // 首先找到要修改的数据,修改完成后,同步到数据库 // NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", @"中二"]; // request.predicate = predicate; // NSArray *array = [self.managedObjectContext executeFetchRequest:request error:nil]; // Student *student = [array objectAtIndex:0]; // student.name = @"中小二"; // student.gender = @"妖"; // // 修改完成后执行save // [self.managedObjectContext save:nil]; // // NSLog(@"name is %@, gender is %@, age is %@", student.name, student.gender, student.age); // 4、删除数据 // 首先找到要删除的数据,然后让数据管理器对象执行delete方法 // NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", @"中小二"]; // request.predicate = predicate; // NSArray *array = [self.managedObjectContext executeFetchRequest:request error:nil]; // Student *student = [array objectAtIndex:0]; // // 数据管理对象删除数据 // [self.managedObjectContext deleteObject:student]; //// [self.managedObjectContext deletedObjects]; // 删除临时数据库中某个试题中的所有数据 // [self.managedObjectContext save:nil]; NSLog(@"%@", [self applicationDocumentsDirectory]); return YES; }

       4>. 小结

    • NSPersistentStoreCoordinator(数据连接器类)做的两件事:

        ①. 关联要存储和操作的实体模型(实体模型由NSManagedObjectModel实体模型类取创建)

        ②. 指定存储的位置和文件类型

    • 上下文(NSManagedObjectContext)关联上NSPersistentStoreCoordinator,下面就可以通过NSManagedObjectContext来操作和保存数据了

    四、CoreData数据库表关系关联操作

      1>. 在创建实体类与属性中已经提到了建立表关系的可视化操作路径,填充好关系名、关系表之后就可以添加表关系,如果要添加一对多的关系,点击添加好的表关系之后,在左边的 Type 选择 To Many 即可。
      2>. 代码实现添加表关系
    // 1、创建班级实体
    LanOuClass *classEntity = [[LanOuClass alloc] initWithEntity:classED insertIntoManagedObjectContext:self.managedObjectContext];
    // 创建教师实体
    LanOuTeacher *lanouTeacher = [[LanOuTeacher alloc] initWithEntity:teacherED insertIntoManagedObjectContext:self.managedObjectContext];
    // 创建学生实体
    LanOuStudent *studentEntity = [[LanOuStudent alloc] initWithEntity:stdentED insertIntoManagedObjectContext:self.managedObjectContext];
    
    // 2、添加一对一表关联
    classEntity.lanouTeacher = [[LanOuTeacher alloc] initWithEntity:teacherED insertIntoManagedObjectContext:self.managedObjectContext];
    
    // 3、添加一对多表关联
    [classEntity addLanouStudentObject:studentEntity]; // 学生和班级建立关联
    [classEntity.lanouTeacher addLanouStudentObject:studentEntity]; // 学生和老师建立关联
    

      3>. 一对多表关系时CoreData自动生成基本操作方法

    - (void)addLanouStudentObject:(LanOuStudent *)value; // 添加一个学生关系
    - (void)removeLanouStudentObject:(LanOuStudent *)value; // 删除一个学生关系
    - (void)addLanouStudent:(NSSet *)values; // 添加一组学生关系
    - (void)removeLanouStudent:(NSSet *)values; // 删除一组学生关系
    

       注:此处只是表间关系删除,并不会删除文件数据

  • 相关阅读:
    【科创人上海行】扶墙老师王福强:架构师创业要突破思维局限,技术人创业的三种模式,健康第一
    【科创人·独家】连续创业者高春辉的这六年:高强度投入打造全球领先的IP数据库
    中国确实需要大力扩充核武器
    SAP MM 可以通过STO在公司间转移质检库存?
    SAP MM 如何看一个采购申请是由APO系统创建后同步过来的?
    SAP MM 如何看一个Inbound Delivery单据相关的IDoc?
    SAP ECC & APO集成
    SAP MM 采购订单收货之后自动形成分包商库存?
    SAP MM 带有'Return'标记的STO,不能创建内向交货单?
    SAP MM 没有启用QM的前提下可以从QI库存里退货给Vendor?
  • 原文地址:https://www.cnblogs.com/hyl2012/p/5244502.html
Copyright © 2020-2023  润新知