CoreData
结构图
1.模型文件
1.1 创建模型文件
1.2 创建实体
点击下面的 Add Entity 按钮可以添加一个Entity,也就是一个数据实体,相当于数据库中的一张表
1.3 图中的 Attributes 是定义属性的地方,Relationships 是定义关联关系的地方,点击加号可以添加。下面来给 UserLandlord1.0 添加三个字段: landlordId, landlordPassword,还可以选中一个字段,可以在右侧的面板中对它做一些自定义:
例如在 validation 里对数据做一些限制,字符串的长度,数字类型的最大最下值;设置索引、默认值等。不同的数据类型可以设置不同的内容,一般维持默认就可以。
另外对于每一个 entity 实体类,Build 过后 Xcode 都会自动帮我们生成相应的实体类代码,生成的代码不会在工程目录中显示出来,但是可以通过导入头文件索引到;当然也可以配置成手动生成的,选中对应的 Entity 然后点击右侧面板的 Codegen,把 ClassDefinition 修改成 Manual/None,然后 Xcode 就不会再自动生成了。
1.4 另外,Xcode 自动生成的代码都是 Swift 语言的,如果想改成Objc,可以在这里改:
注意:下图一定要选这个,否则会报错!
1.5 这个时候也可以通过 Editor -> Create NSManagedObject Subclass 来生成相应的实体类:
需要注意的是,如果前面有自动生成过这些类文件,手动生成后可能会编译出错,因为工程里会索引到两份同样的代码,这个时候需要 Clean 一下工程再 Build 即可。
1.6 下面是自动生成的实体类:
到此为止,CoreData 的数据模型就创建好了。
2. CoreData 栈的创建
数据模型创建好之后,想要使用 CoreData 进行数据持久化,下一步就是初始化 CoreData 栈了。
2.1 CoreData 栈是 CoreData 初始化被访问的框架对象的集合,以及应用中数据对象和外部数据存储的媒介。CoreData 的初始化需要一步步地初始化 CoreData 栈上的三个对象结构,它们分别是:
a. NSManagedObjectModel — 描述了数据模型的结构信息
b. NSPersistentStoreCoordinator — 数据持久层和内存对象模型的协调器
c. NSManagedObjectContext — 内存中 managedObject 对象的上下文
2.2 下图是 CoreData 栈的结构
3.用代码实现
3.1 创建 NSManagedObjectModel 对象,它需要通过上文中讲的数据模型文件来创建
需要导入 “#import <CoreData/CoreData.h>”
1 // 采用懒加载方式,创建管理对象模型 2 - (NSManagedObjectModel *)managedObjectModel{ 3 if (_managedObjectModel) { 4 // url 为ModelLandlord.xcdatamodeld,注意扩展名为 momd,而不是 xcdatamodeld 类型 5 NSURL *modelUrl = [[NSBundle mainBundle] URLForResource:@"ModelLandlord" withExtension:@"momd"]; 6 _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelUrl]; 7 } 8 return _managedObjectModel; 9 }
3.2 创建 NSPersistentStoreCoordinator
创建好 managedObjectModel
后就可以来创建 persistentStoreCoordinator
了,因为它的创建需要用到 managedObjectModel
,managedObjectModel
告诉了persistentStoreCoordinator
数据模型的结构,然后 persistentStoreCoordinator
会根据对应的模型结构创建持久化的本地存储。
1 /* 持久存储调度器 */ 2 - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 3 if (!_persistentStoreCoordinator) { 4 // 创建 coordinator 需要传入 managedObjectModel 5 _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel]; 6 // 指定本地的 sqlite 数据库文件 7 NSURL *sqliteURL = [[self getDocumentURL] URLByAppendingPathComponent:@"ModelLandlord.sqlite"]; 8 NSError *error; 9 // 为 persistentStoreCoordinator 指定本地存储的类型,这里指定的是 SQLite 10 [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sqliteURL options:nil error:&error]; 11 if (error) { 12 NSLog(@"falied to create persistentStoreCoordinator %@", error.localizedDescription); 13 } 14 } 15 return _persistentStoreCoordinator; 16 } 17 18 #pragma mark *** 获取沙盒路径的URL地址 *** 19 - (NSURL *) getDocumentURL { 20 NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 21 return url; 22 }
3.3 创建 NSManagedObjectContext
创建 managedObjectContext
, 这也是平时操作 CoreData 主要会用到的对象
1 - (NSManagedObjectContext *)context { 2 if (!_context) { 3 // 指定 context 的并发类型: NSMainQueueConcurrencyType 或 NSPrivateQueueConcurrencyType 4 _context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 5 _context.persistentStoreCoordinator = self.persistentStoreCoordinator; 6 } 7 return _context; 8 }
至此,CoreData 栈的初始化就创建完成了。以后操作 CoreData 就可以通过 context 属性来完成,操作完之后调用 context
的 save
方法就可以数据持久化到本地。
1 func performBlock(_ block: () -> Void)//在私有队列中异步地执行 Blcok 2 func performBlockAndWait(_ block: () -> Void)//在私有队列中执行 Block 直至操作结束才返回
4. 增、删、查、改
4.1 添加数据
1 - (void)testAddData { 2 // 根据Entity名称和NSManagedObjectContext获取一个新的继承于NSManagedObject的子类Student 3 NSLog(@"--------->%@",self.context); 4 Landlord *landlord = [NSEntityDescription insertNewObjectForEntityForName:@"Landlord" inManagedObjectContext:self.context]; 5 6 // 根据表Landlord中的键值,给NSManagedObject对象赋值 7 landlord.landlordId = @"111111"; 8 landlord.landlordPassword = @"password"; 9 10 // 保存数据 11 NSError *error = nil; 12 if ([self.context save:&error]) { 13 NSLog(@"插入数据成功!"); 14 }else { 15 NSLog(@"数据插入到数据库失败, %@",error); 16 } 17 18 }
4.2 读取数据
1 - (void)testReadData { 2 // 创建查询请求 3 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Landlord"]; 4 // 查询条件 5 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"landlordPassword = %@",@"password"]; 6 request.predicate = predicate; 7 8 // 从第几页开始显示 9 // 通过这个属性实现分页 10 request.fetchOffset = 0; 11 // 每页显示多少条数据 12 request.fetchLimit = 6; 13 14 // 发送查询请求 15 NSArray *resArray = [self.context executeFetchRequest:request error:nil]; 16 NSLog(@"查询的数据是:%@",[resArray.firstObject landlordId]); 17 }
4.3 更新数据
1 - (void)testUpdateData { 2 // 创建查询请求 3 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Landlord"]; 4 NSPredicate *pre = [NSPredicate predicateWithFormat:@"landlordPassword = %@", @"password"]; 5 request.predicate = pre; 6 7 // 发送请求 8 NSArray *resArray = [self.context executeFetchRequest:request error:nil]; 9 // 修改 10 for (Landlord *lan in resArray) { 11 lan.landlordId = @"且行且珍惜_iOS"; 12 } 13 14 // 保存 15 NSError *error = nil; 16 if ([self.context save:&error]) { 17 NSLog(@"更新所有帅哥的的名字为“且行且珍惜_iOS"); 18 }else{ 19 NSLog(@"更新数据失败, %@", error); 20 } 21 22 }
4.4 删除数据
1 - (void)testDeleteData { 2 // 创建删除请求 3 NSFetchRequest *deleRequest = [NSFetchRequest fetchRequestWithEntityName:@"Landlord"]; 4 5 // 删除条件 6 NSPredicate *pre = [NSPredicate predicateWithFormat:@"landlordPassword = %@", @"password"]; 7 deleRequest.predicate = pre; 8 9 // 返回需要删除的对象数组 10 NSArray *deleArray = [self.context executeFetchRequest:deleRequest error:nil]; 11 12 // 从数据库中删除 13 for (Landlord *stu in deleArray) { 14 [self.context deleteObject:stu]; 15 } 16 17 NSError *error = nil; 18 //保存--记住保存 19 if ([_context save:&error]) { 20 NSLog(@"删除 age < 10 的数据"); 21 }else{ 22 NSLog(@"删除数据失败, %@", error); 23 } 24 25 26 }
4.5 排序
1 - (void)sort{ 2 //创建排序请求 3 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Landlord"]; 4 //实例化排序对象 5 NSSortDescriptor *landlordId = [NSSortDescriptor sortDescriptorWithKey:@"landlordId"ascending:YES]; 6 request.sortDescriptors = @[landlordId]; 7 //发送请求 8 NSError *error = nil; 9 NSArray *resArray = [self.context executeFetchRequest:request error:&error]; 10 if (error == nil) { 11 [self alertViewWithMessage:@"按照age和number排序"]; 12 }else{ 13 NSLog(@"排序失败, %@", error); 14 } 15 }
5. CoreData 的调试
选择【Product】【scheme】【Edit scheme】
选择【Arguments】,在【ArgumentsPassed On Launch】添加两个选项:
(1)-com.apple.CoreData.SQLDebug
(2)1