认识CoreData - 初识CoreData

该文章属于刘小壮原创,转载请注明:刘小壮

配图

这段时间公司一直比较忙,和组里小伙伴一起把公司项目按照之前逻辑重写了一下。由于项目比较大,还要兼顾之前项目的迭代和其他项目,目前为止只写完第一阶段。

之前项目本地持久化方案主要用的是SQLite,这次重写项目打算换一种持久化方案,于是我们经过讨论选择了苹果的“亲儿子”CoreData

在使用CoreData的过程中,我也是一边学习一边实践。在学习的过程中,一些写的质量比较高的博客对我的帮助也很大,例如objc.io等博客,在这里就不一一列举出来了,非常感谢这些作者。

先不说项目中用不用得到,其实很多人都是不了解CoreData的,但是经过我的学习发现CoreData还是挺不错的。所以正如这系列文章的名字一样-认识CoreData,打算写这系列文章来认识一下CoreData

这系列博客将从简单到复杂的来讲一下CoreData,其中除了基础使用还会包括多线程、批量数据处理等内容,这些很多都是我公司项目开发过程中接触到的,我们也设想了一些极端的情况,解决方案都会体现在这系列博客中。

本人接触CoreData时间并不长,只是专门花了一段时间学习CoreData。本系列文章偏重于通过图形化界面使用CoreData,不会全部采取纯代码进行CoreData的所有操作,而且那样操作起来也确实比较麻烦,反而就失去了CoreData的优势和本质。

文章中如有疏漏或错误,还请各位及时提出,谢谢!😊


写在前面

CoreData中有一些常用的类,称呼可能各不相同。所以这里先约定一些关键字,以便理解后面的一些内容,这些约定很多都是出现在苹果的官方文档中的。
NSPersistentStoreCoordinator(Persistent Store Coordinator),缩写为PSC
NSManagedObjectContext(Managed Object Context),缩写为MOC
NSManagedObjectModel(Managed Object Model),缩写为MOM
NSManagedObject及其子类,根据英文翻译和其作用,称之为托管对象
后缀名为.xcdatamodeld的文件,因为存储着所有实体的数据结构和表示,所以称之为模型文件

什么是CoreData?

简单介绍一下

CoreData出现在iOS3中,是苹果推出的一个数据存储框架。CoreData提供了一种对象关系映射(ORM)的存储关系,类似于Javahibernate框架。CoreData可以将OC对象存储到数据库中,也可以将数据库中的数据转化为OC对象,在这个过程中不需要手动编写任何SQL语句,这是系统帮我们完成。

CoreData最大的优势就是使用过程中不需要编写任何SQL语句,CoreData封装了数据库的操作过程,以及数据库中数据和OC对象的转换过程。所以在使用CoreData的过程中,很多操作就像是对数据库进行操作一样,也有过滤条件、排序等操作。

这就相当于CoreData完成了Model层的大量工作,例如Model层的表示和持久化,有效的减少了开发的工作量,使Model层的设计更加面向对象。

CoreData好用吗?

之前听人说过,CoreData比较容易入手,但是很难学精。这也是很多人说CoreData不好用的原因之一,只是因为使用方式有问题,或者说并没有真正掌握CoreData

如果从性能上来说,CoreDataSQLite确实略差一些。但是对于移动端来说,并不需要大型网站的高并发,所以这点性能差别几乎是没有影响的,所以这点可以忽略不计。在后面的文章中,将会给出CoreData的优点和缺点对比,以及详细的性能测评。

CoreData主要的几个类
  • NSManagedObjectContext
    托管对象上下文,进行数据操作时大多都是和这个类打交道。
  • NSManagedObjectModel
    托管对象模型,一个托管对象模型关联一个模型文件(.xcdatamodeld),存储着数据库的数据结构。
  • NSPersistentStoreCoordinator
    持久化存储协调器,负责协调存储区和上下文之间的关系。
  • NSManagedObject
    托管对象类,所有CoreData中的托管对象都必须继承自当前类,根据实体创建托管对象类文件。
CoreData简单创建流程
  1. 模型文件操作
    1.1 创建模型文件,后缀名为.xcdatamodeld。创建模型文件之后,可以在其内部进行添加实体等操作(用于表示数据库文件的数据结构)
    1.2 添加实体(表示数据库文件中的表结构),添加实体后需要通过实体,来创建托管对象类文件。
    1.3 添加属性并设置类型,可以在属性的右侧面板中设置默认值等选项。(每种数据类型设置选项是不同的)
    1.4 创建获取请求模板、设置配置模板等。
    1.5 根据指定实体,创建托管对象类文件(基于NSManagedObject的类文件)

  2. 实例化上下文对象
    2.1 创建托管对象上下文(NSManagedObjectContext)
    2.2 创建托管对象模型(NSManagedObjectModel)
    2.3 根据托管对象模型,创建持久化存储协调器(NSPersistentStoreCoordinator)
    2.4 关联并创建本地数据库文件,并返回持久化存储对象(NSPersistentStore)
    2.5 将持久化存储协调器赋值给托管对象上下文,完成基本创建。

CoreData结构

CoreData的结构构成

之前看到过几张介绍CoreData结构的图片,感觉其表示的结构比较清晰。可以通过这几张图片初步认识一下CoreData,在后面的文章中还会对这几个类进行详细解释。

整体结构

上图中是初始化MOC所涉及到的一些类,由这些类实例化并最终构成可以使用的MOC。图中编号是实例化一个具备数据处理能力的MOC过程,这个过程和上面介绍过的实例化上下文对象相同。

NSManagedObjectContext

PSC创建并关联本地数据库,并设置为MOCpersistentStoreCoordinator属性后,MOC就具备对当前存储区所有托管对象操作的能力。但是需要注意的是,MOC对托管对象是懒加载的,在使用时才会被加载到MOC的缓存中。

NSManagedObjectModel

MOM对象加载模型文件后,获取到模型文件中所有实体的构成结构。由于MOM中存储着模型文件的结构,PSC需要通过MOM对象实例化本地数据库。

Entity

所有属性都存在Entity中,以及有关联关系的属性和请求模板,这都会在后面的章节中讲到。

NSManagedObject

可以通过Entity创建继承自NSManagedObject类的文件,这个文件就是开发中使用的托管对象,具备模型对象的表示功能,CoreData的本地持久化都是通过这个类及其子类完成的。

持久化存储调度器

CoreData的整体结构中,主要分为两部分。一个是NSManagedObjectContext管理的模型部分,管理着所有CoreData的托管对象。一个是SQLite实现的本地持久化部分,负责和SQL数据库进行数据交互,主要由NSPersistentStore类操作。这就构成了CoreData的大体结构。

结构图

从图中可以看出,这两部分都是比较独立的,两部分的交互由一个持久化存储调度器(NSPersistentStoreCoordinator)来控制。上层NSManagedObjectContext存储的数据都是交给持久化调度器,由调度器调用具体的持久化存储对象(NSPersistentStore)来操作对应的数据库文件,NSPersistentStore负责存储的实现细节。这样就很好的将两部分实现了分离。

个人随想

对于CoreData的整体结构,因为CoreData底层存储本来就是用SQLite实现的,所以我用CoreData的结构和SQLite对比了一下,发现还是很多相似之处的。

.xcdatamodeld文件代表着数据库文件结构,通过.xcdatamodeld编译后的.momd文件生成数据库。每个实体代表一张数据表,实体之间的关联关系就是SQLite的外键。

下图就是CoreData底层存储的结构,用红圈圈住的部分指向关联表的主键下标。例如1就指向关联表的主键下标为1的行。

外键

CoreData杂谈

CoreData数据存储安全

CoreData本质还是使用SQLite进行存储,并没有另外提供加密功能,具体的数据加解密还需要自己完成。

CoreData在硬盘上的数据存储结构

数据库存储结构

通过PSC指定创建SQLite目录后,会在指定的目录下生成一个数据库文件,同时还会生成两个同名但后缀不同的文件,其中只有后缀.sqlite的文件是存储数据的文件。

这个数据库文件中会默认生成三个表,Z_METADATAZ_PRIMARYKEYZ_MODELCACHE,其他我们自己的表也都是大写Z开头的。

在每个表中,系统还会默认生成三个字段,Z_PKZ_ENTZ_OPT三个字段,也都是大写Z开头并且带下划线的。其他字段就是我们自己的字段了,大写Z开头但不带下划线。

CoreData执行效率

现在市面上的大多数项目,都是使用SQLite作为持久化的方案,而CoreData的使用并不是很普遍。对于这个问题,我认为首先是很多项目开始的比较早,那时候好多iOS程序员都是从其他语言转过来的,更加熟悉SQLite,所以用SQLite比较多一些。后面如果不进行大的项目重构,就很难换其他的持久化方案了。

还有就是不熟悉CoreData,也不想去了解和深入学习CoreData,我认为这是很大的原因。所以项目中用CoreData的人并不多,而真正掌握CoreData技术的人更少。

之前听其他人说CoreData的执行效率不如SQLite高,这个如果深究的话,确实CoreData要比SQLite效率差一些,只不过并没有太大区别。CoreData本质也是在底层执行SQL语句,只是CoreDataSQL语句执行逻辑比较耗时,没有手动编写SQL语句更加直接。我们可以将CoreData的调试功能打开,具体看一下SQL语句的执行。

这里要说一点,客户端毕竟不是服务端,不需要像服务器那样大量的数据查询,所以CoreData是完全可以应对客户端的查询量的。如果从灵活性来说,CoreData确实没有SQLite的灵活性高,一些SQLite的复杂功能可能也不能实现,但是就目前大多数项目来说,CoreData已经能够满足项目持久化需求了。

导致执行效率差异的原因还体现在对象转换上,CoreData在执行SQL语句的基础上,还多了一层将数据映射给托管对象的操作,这样得到的就是OC的托管对象,而SQLite得到的则不是。如果给SQLite执行完成后,也加一层创建托管对象并赋值的操作,这时候对比性能两者的差距可能就会更小了。

性能评测

下面是一篇关于CoreDataFMDBRealm性能测试结果的博客,最后的结果我也没有去验证,只是大致看了一下代码还是比价靠谱的。作者测试Demo原文地址

** 测试数据的数量是以K为单位,最少为1K的数据量。涉及到的操作主要是下面四种**:

  1. 新建数据库并插入1K条数据。
  2. 已有数据库,插入1K条数据。
  3. 查询总量为10K条数据,连续查询单次为1K数据。
  4. 10K条数据总量,更新其中1K条数据的部分字段性能。
性能评测结果:

根据测试结果可以发现,在前面两种插入操作,CoreData的性能比FMDBRealm要快很多。

而对于查询操作,CoreData比其他两种操作耗时多很多,大概多出三四倍。这很可能和CoreData将查询结果的数据转为托管对象有关系,抛去CoreData这部分转换操作性能会比现在好很多。

而更新操作则直接基于SQLite封装的FMDB有绝对的优势,FMDB和其他两种操作差距大概是十倍左右,而其他两种操作性能差不多。当然CoreData也存在着上面提到的对象转换操作,CoreData抛去这步结果可能会比现在好很多。

测试图表

下面的测试数据中,取得是三次测试结果的平均值。

第三方 编号
CoreData 1
FMDB 2
Realm 3
新建数据库并插入1K条数据
已有数据库,插入1K条数据
查询总量为10K条数据,连续查询单次为1K数据
10K条数据总量,更新其中1K条数据的部分字段性能

CoreData调试

Xcode调试命令

CoreData本质上是对SQLite的一个封装,在内部将对象的持久化转化为SQL语句执行,可以在项目中将CoreData调试打开,从而可以看到CoreDataSQL语句执行和一些其他log信息。

  1. 打开Product,选择Edit Scheme.
  2. 选择Arguments,在下面的ArgumentsPassed On Launch中添加下面两个选项。
    (1)-com.apple.CoreData.SQLDebug
    (2)1
终端调试命令

如果是在模拟器上调试程序,可以通过 sqlite3 /数据库路径/ 命令来查看和操作数据库。
.tables 查看当前数据库文件中所有的表名
select *from tableName 执行查询的SQL语句

终端调试命令

好多同学都问我有Demo没有,其实文章中贴出的代码组合起来就是个Demo。后来想了想,还是给本系列文章配了一个简单的Demo,方便大家运行调试,后续会给所有博客的文章都加上Demo

Demo只是来辅助读者更好的理解文章中的内容,应该博客结合Demo一起学习,只看Demo还是不能理解更深层的原理Demo中几乎每一行代码都会有注释,各位可以打断点跟着Demo执行流程走一遍,看看各个阶段变量的值。

Demo地址刘小壮的Github


这两天更新了一下文章,将CoreData系列的六篇文章整合在一起,做了一个PDF版的《CoreData Book》,放在我Github上了。PDF上有文章目录,方便阅读。

如果你觉得不错,请把PDF帮忙转到其他群里,或者你的朋友,让更多的人了解CoreData,衷心感谢!😁

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

推荐阅读更多精彩内容

  • 该文章属于刘小壮原创,转载请注明:刘小壮[https://www.jianshu.com/u/2de707c93d...
    刘小壮阅读 26,952评论 75 85
  • 该文章属于刘小壮原创,转载请注明:刘小壮[https://www.jianshu.com/u/2de707c93d...
    刘小壮阅读 16,998评论 62 62
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,391评论 25 707
  • 孩子刚刚升小学三年级,第一个单元的习作就是要求孩子写一篇关于课余生活的文章,于是本文应运而生。
    邱Q糖阅读 279评论 0 2
  • 麻木的错觉,头脑昏沉 感觉把自己围进了一个圈子 周围的变化让我闪躲不及 像丧尸一样允吸着气味 渴望堕落的窒息感 如...
    导演张升志阅读 219评论 0 0