(一)CoreData - 基本使用

作者: 徊家喂猪 | 来源:发表于2017-04-21 20:22 被阅读54次

    (一)CoreData - 基本使用

    @(HTML5秘籍)[Objective-c, iOS, 本地存储]


    @一张占位图,心旷神怡的开始阅读吧

    题目虽然说的是快速入门,但是CoreData是一门很博大精深的技术,还是不要妄想几天之内能融会贯通。接下来几篇文章会由浅入深,逐步讲解如何使用并掌握CoreData

    最近一直在找一些关于日程管理的软件,有一些感觉还不错的,但是总觉得自己想要一些功能都没有,所以干脆就下手自己写一个自己的。由于没有后台服务器做接口,一些数据只能暂时做本地存储。在技术选型的时候做了一些调查,因为之前做过PHP,对SQL印象蛮好的。但是对于一个移动端应用来说,基本不需要大量的存储数据,因此在FMDB,Realm和CoreData之间,选择了苹果的亲儿子CoreData。

    [TOC]

    封装CoreData管理工具

    1. 创建一个自带CoreData代码的工程

    在Xcode创建工程的时候,就可以创建一个带有CoreData的工程,在APPdelegate中会生成关于CoreData的代码。


    @创建带有CoreData的工程

    下图是Xcode7自动创建的CoreData代码,Xcode 8 做了修改,我们先说一下旧版的怎么玩,然后再看看新版怎么弄。

    @Xcode 7自动创建的CoreData代码1
    @Xcode 7自动创建的CoreData代码2

    虽然说已经生成了这些代码,但是还是不能直接用,我们需要将代码重新封装一下。

    2. 简单封装CoreData管理类

    ① 创建一个继承于NSObject的类 LTCoreDataManager

    ② 写一个单例作为初始化方法

    + (LTCoreDataManager *)shareLTCoreDataManager
    {
        static LTCoreDataManager *manager = nil;
    
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            manager = [[LTCoreDataManager alloc] init];
        });
    
        return manager;
    }
    

    ③ 将自动生成的代码粘贴到 LTCoreDataManager.m 中

    ④ 在 LTCoreDataManager.h 中加入方法声明

    + (LTCoreDataManager *)shareLTCoreDataManager;
    
    @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
    @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
    @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
    
    - (void)saveContext;
    - (NSURL *)applicationDocumentsDirectory;
    

    ⑤ 注意:应在 LTCoreDataManager.h 中引入 <CoreData/CoreData.h>

    创建CoreData模型文件

    1.构建模型文件

    在创建工程的时候,如果选择了使用CoreData,Xcode会自动生成一个模型文件,模型文件的后缀为.xcdatamodeld。如果没有选择自动生成模型文件,我们可以手动创建一个模型文件Command + N,选择 Core Data -> Data Model -> Next

    @创建好的模板

    左侧有三个选项,entitiesfetch requestsconfigurations

    2.创建实体

    长按左下方的 Add Entity 按钮,会弹出菜Add EntityAdd Fetch RequestAdd Configuration。选择 Add Entity创建一个实体,命名为Plan。如下图所示

    @Plan Entity

    右侧对应着Attributes(属性)、Relationships(关联关系)、Fetched Properties(获取操作)。
    首先,添加两个属性,planName:type 为 String,planId:type 为 Integer64。
    需要注意的是,属性的首字母要小写。

    关于Type类型的说明

    • Undefined: 默认值,参与编译会报错
    • Integer 16: 整数,表示范围 -32768 ~ 32767
    • Integer 32: 整数,表示范围 -2147483648 ~ 2147483647
    • Integer 64: 整数,表示范围 –9223372036854775808 ~ 9223372036854775807
    • Float: 小数,通过MAXFLOAT宏定义来看,最大值用科学计数法表示是 0x1.fffffep+127f
    • Double: 小数,小数位比Float更精确,表示范围更大
    • String: 字符串,用NSString表示
    • Boolean: 布尔值,用NSNumber表示
    • Date: 时间,用NSDate表示
    • Binary Data: 二进制,用NSData表示
    • Transformable: OC对象,用id表示。可以在创建托管对象类文件后,手动改为对应的OC类名。使用的前提是,这个OC对象必须遵守并实现NSCoding协议。

    3.添加关联关系

    再创建一个实体Task并添加响应的属性。

    @添加关联关系

    Task添加关联关系,点击Relationships下面的加号,新建一个关联关系,命名为planinverse需要设置好Relationships之后才能设置。

    关联关系设置

    • delete rule: 定义关联属性的删除规则。在当前对象和其他对象有关联关系时,当前对象被删除后与之关联对象的反应。这个参数有四个枚举值,代码对应着模型文件的相同选项。
    1. NSNoActionDeleteRule 删除后没有任何操作,也不会将关联对象的关联属性指向nil。删除后使用关联对象的关联属性,可能会导致其他问题。
    2. NSNullifyDeleteRule 删除后会将关联对象的关联属性指向nil,这是默认值。
    3. NSCascadeDeleteRule 删除当前对象后,会将与之关联的对象也一并删除。
    4. NSDenyDeleteRule 在删除当前对象时,如果当前对象还指向其他关联对象,则当前对象不能被删除。
    • Type: 主要有两种类型,To One和To Many,表示当前关系是一对多还是一对一。

    4.创建托管对象类文件

    创建文件
    选中后缀名为.xcdatamodeld的模型文件,选择XcodeEditor -> Create NSManagedObject Subclass -> 选择模型文件 -> 选择实体,生成实体对应的托管对象类文件。

    @生成的文件

    更新文件
    当前模型对应的实体发生改变后,需要重新生成模型文件。生成步骤和上面一样,主要是替换Category文件,托管对象文件不会被替换。生成文件时不需要删除,直接替换文件。

    增删改查操作

    1.插入操作

    // 创建托管对象,并指明创建的托管对象所属实体名
    Plan *planObj = [NSEntityDescription insertNewObjectForEntityForName:@"Plan" inManagedObjectContext:context];
    planObj.planName = @"计划名字";
    planObj.planId = [NSNumber numberWithInteger:1];
    
    // 通过上下文保存对象,并在保存前判断是否有更改
    NSError *error = nil;
    if (context.hasChanges) {
        [context save:&error];
    }
    
    // 错误处理
    if (error) {
        NSLog(@"CoreData Insert Data Error : %@", error);
    }
    

    通过NSEntityDescriptioninsert类方法,生成并返回一个Employee托管对象,并将这个对象插入到指定的上下文中。
    managedObjectContext将操作的数据存放在缓存层,只有调用managedObjectContextsave方法后,才会真正对数据库进行操作,否则这个对象只是存在内存中,这样做避免了频繁的数据库访问。

    2.删除操作

    // 建立获取数据的请求对象,指明对Plan实体进行删除操作
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Plan"];
    
    // 创建谓词对象,过滤出符合要求的对象,也就是要删除的对象
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"planName = %@", @"计划名字"];
    [request setPredicate:predicate];
    
    // 执行获取操作,找到要删除的对象
    NSError *error = nil;
    NSArray<Plan *> *planArr = [context executeFetchRequest:request error:&error];
    
    // 遍历符合删除要求的对象数组,执行删除操作
    [planArr enumerateObjectsUsingBlock:^(Plan * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [context deleteObject:obj];
    }];
    
    // 保存上下文
    if (context.hasChanges) {
        [context save:nil];
    }
    
    // 错误处理
    if (error) {
        NSLog(@"CoreData Delete Data Error : %@", error);
    }
    

    3.更新操作

    // 建立获取数据的请求对象,并指明操作的实体为Plan
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Plan"];
    
    // 创建谓词对象,设置过滤条件
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"planName = %@", @"计划名字"];
    request.predicate = predicate;
    
    // 执行获取请求,获取到符合要求的托管对象
    NSError *error = nil;
    NSArray<Plan *> *planArr = [context executeFetchRequest:request error:&error];
    [planArr enumerateObjectsUsingBlock:^(Plan * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        obj.planId = @2;
    }];
    
    // 将上面的修改进行存储
    if (context.hasChanges) {
        [context save:nil];
    }
    
    // 错误处理
    if (error) {
        NSLog(@"CoreData Update Data Error : %@", error);
    }
    

    4.查询操作

    // 建立获取数据的请求对象,指明操作的实体为Plan
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Plan"];
    
    // 执行获取操作,获取所有Plan托管对象
    NSError *error = nil;
    NSArray<Plan *> *planArr = [context executeFetchRequest:request error:&error];
    [planArr enumerateObjectsUsingBlock:^(Plan * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"Plan Name : %@, Id : %@", obj.planName, obj.planId);
    }];
    
    // 错误处理
    if (error) {
        NSLog(@"CoreData Ergodic Data Error : %@", error);
    }
    

    小结一下

    看完上面一大堆,其实应该还是不太理解。不过跟着步骤一步步走下来,应该是可以简单实用了。

    相关文章

      网友评论

        本文标题:(一)CoreData - 基本使用

        本文链接:https://www.haomeiwen.com/subject/qlkjzttx.html