引言
CoreData是Apple官方为iOS提供的一个数据持久化方案,其本质是一个通过封装底层数据操作,让程序员以面向对象的方式存储和管理数据的ORM框架(Object-Relational Mapping:对象-关系映射,简称ORM)。虽然底层支持SQLite、二进制数据、xml等多种文件存储,但是主要还是用来操作SQLite数据库。
程序员不需要学习或者使用SQL语句,只需要使用CoreData框架提供的对象和接口以及图形化工具,即可完成SQLite数据库的创建、表关系、增删改查等一系列操作,在一定程度上降低了程序员的学习成本并增加了代码的统一性和可阅读性。
框架结构
CoreData作为一个ORM框架,需要解决实体对象和数据库数据的映射关系,将OC对象转化为数据,保存到SQLite文件中,同时能将保存在数据库中的数据还原成OC对象。概要结构如下:
CoreData主要包含以下几个类:
NSManagedObjectModel:托管对象模型,映射实体类和数据库数据的关系,本质是一个XML文件,后面简称MOM
NSManagedObject:托管对象,对应数据库数据的实体,后面简称MO
NSManagedObjectContext:托管对象上下文,管理托管对象,后面简称MOC
NSPersistentStoreCoordinator:持久化存储调度器,用来处理磁盘持久化数据和实体类对象的相互转化,后面简称PSC
NSPersistentStore:持久化存储器,负责磁盘持久化数据存取,后面简称PS
CoreData的总体框架如下图:
在上层通过MOC操作对应的托管对象,然后MOC会将操作传递给PSC,PSC通过托管对象模型中的映射关系,再将托管对象的操作转化为对底层数据的操作,进行数据存取操作。
CoreData使用流程
创建和配置模型文件
a. 新建项目是勾选Use CoreData,xcode会自动创建模型文件;
b. 如果新建项目时未勾选,可以通过新建文件手动创建;
c. 通过图形化工具即可配置实体类和数据库表的映射,实体类之间的关系,以及简单的查询策略;
d. 配置好模型文件后,xcode8版本之前需要手动生成实体类,选中entity -> 菜单栏Editor -> Create NSManagedObject SubClass即可手动生成托管实体类。xcode8版本以后会自动生成实体类,默认在项目中不会显示。如果想要查看实体类结构,可以在模型文件中配置『Codegen』为『Manual/None』,然后再手动生成,否则会存在两份实体类,编译报错;
e. 对应每个实体类会使用category的方式生成如图4个文件,继承自NSManagedObject,托管实体类的属性用@dynamic修饰,CoreData框架会在运行时动态生成存取方法;
f.这样就完成了数据模型文件创建和简单使用,在代码中初始化即可使用。
使用数据模型MOM初始化持久化存储调度器PSC,然后使用持久化存储类型和路径配置持久存储器PS,最后将PS添加到PSC即可。
初始化托管对象上下文MOC,并配置队列的类型,队列类型是一个枚举值,跟CoreData多线程相关(后文会详细介绍),有三种类型:
NSMainQueueConcurrencyType:主并发队列,UI相关操作建议使用该队列
NSPrivateQueueConcurrencyType:私有并发队列,会在子线程执行操作,耗时操作建议使用
NSMainQueueConcurrencyType:已废弃
将MOC和PSC关联,即完成了CoreData的初始化和配置工作。
基本使用
输出SQL语句日志
使用CoreData操作数据库,默认是没有底层操作数据库的相关SQL语句的,可以通过配置project -> schema -> edit schema - run开启,如下图:
数据库插入操作
使用NSEntityDescription类工厂方法传入要插入的托管对象类和指定托管对象所在的上下文获取到托管对象MO
对MO进行赋值
调用当前MOC的save方法就可以完成数据库的插入操作
数据库删除操作
直接调用托管对象上下文MOC删除管理的托管对象即可完成数据库记录的删除操作
正常情况下,当前是没有要删除的托管对象的,因此需要先调用查询找到要删除的MO,然后调用删除
数据库更新操作
使用CoreData进行数据库更新操作和删除很类似:
首先通过查询获取到要更新的托管对象
直接对托管对象进行处理
将托管对象的更新操作保存到数据库
数据库查询操作
CoreData将查询操作进行了很好的封装,不需要使用SQL语句,使用NSFetchRequest(查询请求)和NSPredicate(谓词)来完成查询:
通过NSFetchRequest指定要查询的类
通过NSPredicate指定查询条件
调用MOC执行查询请求即可完成查询
NSFetchRequest提供了参数resultType,是一个枚举类型,可以通过这个参数,设置执行fetch操作后返回的数据类型:
NSManagedObjectResultType: 返回值是MO的子类,也就是托管对象,这是默认选项
NSManagedObjectIDResultType: 返回NSManagedObjectID类型的对象,也就是NSManagedObject的ID,对内存占用比较小。MOC可以通过NSManagedObjectID对象获取对应的托管对象
NSDictionaryResultType: 返回字典类型对象
NSCountResultType: 返回请求结果的count值,不会加载托管对象到内存
使用进阶
数据库复杂查询
上一节在初始化CoreData堆栈后,使用MO和MOC,配合NSFetchRequest和NSPredicate即可完成数据库的基本增删改查操作,这一节介绍基于CoreData的复杂查询,而查询的关键在于熟悉和使用NSPredicate。
NSPredicate
官方的解释:
The NSPredicate class is used to define logical conditions used to constrain a search either for a fetch or for in-memory filtering.
NSPredicate类是用来定义逻辑条件约束的获取或内存中的过滤搜索,支持的基本运算如下:
模糊和多条件查询
排序和分页
批量操作
在CoreData中操作大量数据时,如果将大量MO加载到内存再进行数据更新,会占用大量内存,在移动设备有限的内存上明显会造成瓶颈,因此在iOS8 增加了”Batch Updates”,又在 iOS9 增加了”Batch Deletions”,其根本思路是绕开使用MOC将数据全部加载到内存而直接进行底层数据库操作。
批量更新
NSBatchUpdateResult用来做批量更新,指定要批量更新的MO,即数据库表
初始化查询条件
通过配置propertiesToUpdate批量修改的属性和和要修改的值,为一个dictionary
设置批量更新放回的结果集类型,设置后返回结果会存到NSBatchUpdateResult的result属性中
NSStatusOnlyResultType:默认值,只返回批量更新的结果 YES:成功 / NO : 失败
NSUpdatedObjectIDsResultType:返回批量更新后的MO的id数组
NSUpdatedObjectsCountResultType:返回批量更新后的数量
调用MOC执行批量更新操作,并获取结果。由于批量更新会绕过MOC直接进行数据库操作,因此需要重新执行查询或手动同步数据变化到MOC
批量删除
初始化批量删除request,系统提供两种初始化方法
initWithFetchRequest:通过fetchRequest设置要删除的数据,需要先初始化fetchRequest指定要删除的数据
initWithObjectIDs:使用要删除的托管对象的id来指定要删除的数据,需要先查询出删除对象的id数组
和批量更新一样,可以指定批量删除的操作结果
NSStatusOnlyResultType:默认值,只返回批量删除的结果 YES:成功 / NO : 失败
NSUpdatedObjectIDsResultType:返回批量删除更新后的MO的id数组,用来同步变化到MOC
NSUpdatedObjectsCountResultType:返回批量删除后的数量
根据操作结果进行相关操作
批量读取
平常使用CoreData进行查询操作时,使用NSFetchRequest,并调用MOC的executeFetchRequest:error:方法,会更新MOC管理的MO,然后直接执行并返回结果集。这个过程是同步的,会阻塞当前的MOC。
针对该问题,iOS增加了Asynchronous Fetching查询方法,执行后不会马上返回执行后的结果,并且不会阻塞当前的MOC,测试发现会先执行其它的数据库操作,操作完后执行异步查询。最后执行完后会执行回调block,暂时未发现这种方式的引用场景。
领取专属 10元无门槛券
私享最新 技术干货