Core Data的简单使用

Core Data允许用户使用代表实体和实体间关系的高层对象来操作数据。它也可以管理序列化的数据,提供对象生存期管理与object graph管理,包括存储。Core Data直接与SQLite交互,避免开发者使用原本的SQL语句。-------维基百科

  • Core Data 简介
  • Core Data 快速体验
    • 演练目标
    • 演练步骤
  • Core Data 架构初探
    • 探究Core Data
    • 实现的步骤

Core Data 简介

  • Core Data 是 iOS SDK 里的一个很强大的框架,允许程序员以面向对象的方式储存和管理数据
  • Core Data 不是一个数据库,不要用数据库的眼光去看待 Core Data
  • Core Data 不仅是一个加载、保存数据的框架,还可以
    • 实体 与 SQLite 中的 Table 对应
    • 无需编写任何 SQL 语句
    • 通过 谓词 指定查询条件
  • Core Data 是一套非常成熟的框架,性能优异
    • 最早出现在 Mac OS X 10.4 Tiger 与 iOS 3.0 系统
    • 经过成千上万的应用程序以及数以百万用户的反复的验证
    • 苹果官方应用的数据存储几乎都使用 Core Data

Core Data 快速体验

演练目标
  • 建立个人记录
  • 实现增/删/改/查
    • 演练提示:演练过程中:1. 有些不熟悉的类和方法不要过于纠结。2. 待大家对 Core Data 的基本使用有了一个概念之后,会带领大家探索 Core Data 的架构原理

演练步骤
  • 第一步:新建项目
    • 新建项目,勾选 Use Core Data
  • 第二步:界面准备
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:@"" preferredStyle:UIAlertControllerStyleAlert];

[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
    textField.placeholder = @"请输入用户名";
}];
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
    textField.placeholder = @"请输入年龄";
}];

[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
[alert addAction:[UIAlertAction actionWithTitle:@"保存" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {

    // ...
}]];

[self presentViewController:alert animated:YES completion:nil];

  • 第三步:创建数据模型

    • 实体 (entity) 是数据模型的基石
    • 一个实体表示应用程序中有意义的一部分数据
    • 可以把实体看待成 SQLite 中的一个表,或者数据模型
    • 创建实体对应的代码文件
      • 选择菜单 Editor / Create NSManagedObject SubClass
      • 确认导出文件的类型是 Objective-C
      • 导出文件时注意选择 Group
  • 第四步:新增数据

// 获取上下文
NSManagedObjectContext *moc = self.appDelegate.persistentContainer.viewContext;

// 实例化 Person 对象 - 创建一个实体描述,指定实体名称,要和数据模型行中的实体名称一致
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:moc];

// 设置 person 的属性
person.name = alert.textFields[0].text;
person.age = alert.textFields[1].text.intValue;

// 保存到数据库
[self.appDelegate saveContext];


  • 第五步:查询数据

    • 要查询数据需要使用 查询结果控制器 -> NSFetchedResultsController
    • 实例化查询结果控制器
    • 执行查询 performFetch
    • 查询结果 fetchedObjects
    • 设置代理,监听数据变化 controllerDidChangeContent:
    NSManagedObjectContext *moc = self.appDelegate.persistentContainer.viewContext;

// 查询个人记录的请求
NSFetchRequest *request = [Person fetchRequest];

request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]];

// 实例化查询控制器
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:moc sectionNameKeyPath:nil cacheName:nil];

// 开始查询
[_fetchedResultsController performFetch:NULL];
    
  • 第六步:修改
    • 获取要修改的 实体描述
    • 设置对象属性
    • 保存数据
  • 第七步:删除
    • 获取要删除的 实体描述
    • 让管理上下文删除对象 —— 从内存删除
    • 保存对数据的操作 —— 从数据库中删除
  • 第八步:快速体验小结
    • 纯面向对象开发
    • 不需要编写 SQL
    • 简单、简单、还是简单

Core Data 架构初探

探究Core Data
  • Core Data 核心对象

    • NSPersistentContainer 持久化容器 - iOS 10 新增
      • NSManagedObjectContext 管理对象上下文
        • 负责实体对象管理
        • 以面向对象的方式实现数据的增/删/改/查
      • NSManagedObjectModel 管理对象模型
        • 定义要管理的数据实体模型
      • NSPersistentStoreCoordinator 持久化存储调度器
        • 建立与底层 SQLite 数据库的持久化连接
        • 负责数据存储
    • 注意:Core Data 的核心对象都不是线程安全的
  • 阅读 AppDelegate 模板代码

    • 问题:为什么系统生成的模板中把 Core Data 的基础准备都放在 AppDelegate 中?
      • Core Data 基础准备代码比较繁琐,不容易记忆
      • Core Data 基础准备一经完成,无需修改,可以直接使用
      • 数据存储操作有可能发生在任一界面,Core Data 操作对象定义在 AppDelegate 中本质上就是单例设计模式的一种表现
实现的步骤
  • 第一步:建立 CoreData 工具单例
  • 第二步:复制并解读持久化容器属性
    • 定义 NSPersistentContainer 属性,iOS 10.0 新增
    • 实现 getter 方法

@synthesize persistentContainer = _persistentContainer;

- (NSPersistentContainer *)persistentContainer {

    // 1. 同步所锁,保证线程安全,因为 Core Data 的核心对象都不是线程安全的
    @synchronized (self) {
        if (_persistentContainer == nil) {

            // 0> 将 mainBundle 中的所有数据模型合并成一个 model 对象
            NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];

            // 1> 实例化持久化容器,并且指定保存的数据库名称
            _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"com.GL.database" managedObjectModel:model];

            // 2> 同步加载持久化存储,创建数据库
            [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {

                if (error != nil) {
                    NSLog(@"加载数据存储失败 %@", error);

                    _persistentContainer = nil;
                }
            }];
        }
    }

    return _persistentContainer;
}


  • 常见的错误原因包括:
    • 目录不存在,无法创建数据库文件,或者禁止写入
    • 由于权限或者设备锁定时的数据保护,不能访问持久化存储
    • 设备存储空间不足
    • 数据库不能被迁移到当前模型版本
  • 第三步:Core Data Stack 示意图
  • 第四步:针对早期版本兼容
    • 实例化管理上下文
    • 管理对象模型(实体)
    • 持久化存储调度器
    • 添加数据库
    • 【关键点】给管理上下文指定存储调度器
@synthesize moc = _moc;

- (NSManagedObjectContext *)moc {

    @synchronized (self) {

        // 1. 实例化管理上下文
        _moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

        // 2. 管理对象模型(实体)
        NSManagedObjectModel *mom = [NSManagedObjectModel mergedModelFromBundles:nil];

        // 3. 持久化存储调度器
        NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];

        // 4. 添加数据库
        /**
         1> 数据存储类型
         3> 保存 SQLite 数据库文件的 URL
         */
        NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
        NSString *path = [cacheDir stringByAppendingPathComponent:@"com.GL.db"];
        // 将本地文件的完整路径转换成 文件 URL
        NSURL *url = [NSURL fileURLWithPath:path];

        [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:NULL];

        // 5. 给管理上下文指定存储调度器
        _moc.persistentStoreCoordinator = psc;
    }

    return _moc;
}


  • 第五步:数据迁移
    • 注意
      • 在开发中不要修改数据字段名称
      • 在开发中不要修改数据字段名称
NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption: @(YES),
                       NSInferMappingModelAutomaticallyOption: @(YES)};
[psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:options error:NULL];

  • 第六步:强调线程安全
if (_moc != nil) {
    return _moc;
}

// 互斥锁,应该锁定的代码尽量少!
@synchronized (self) {

  • 第七步:保存上下文
- (void)saveContext {
    NSManagedObjectContext *context = self.moc;

    // 判断上下文中是否有数据发生变化
    // `事务` 可以保存多个数据,不一定每次数据变化都需要保存,例如:for 增加多条记录,就可以最后调用一次保存操作即可!
    if (![context hasChanges]) {
        return;
    }

    // 保存数据
    NSError *error = nil;

    if (![context save:&error]) {
        NSLog(@"保存数据出错 %@, %@", error, error.userInfo);
    }
}



最后感谢大家最近的支持,写下去会更加有动力,请动动你的小手点击赞,再次感谢大家的支持!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容