(一)CoreData - 基本使用

(一)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);
}

小结一下

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容