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);
}
}
最后感谢大家最近的支持,写下去会更加有动力,请动动你的小手点击赞,再次感谢大家的支持!