认识CoreData - MagicalRecord

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


配图

到目前为止,已经将CoreData相关的知识点都讲完了。

在这篇文章中,主要讲一个CoreData第三方库-MagicalRecord。目前为止这个第三方在Github上有9500+Star,是所有CoreData第三方库中使用最多、功能最全的。在文章的后面还会对CoreData做一个总结,以及对本系列所有文章做一个总结。

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


MagicalRecord

CoreData是苹果自家推出的一个持久化框架,使用起来更加面向对象。但是在使用过程中会出现大量代码,而且CoreData学习曲线比较陡峭,如果掌握不好,在使用过程中很容易造成其他问题。

国外开发者开源了一个基于CoreData封装的第三方——MagicalRecord,就像是FMDB封装SQLite一样,MagicalRecord封装的CoreData,使得原生的CoreData更加容易使用。并且MagicalRecord降低了CoreData的使用门槛,不用去手动管理之前的PSCMOC等对象。

根据GithubMagicalRecord的官方文档,MagicalRecord的优点主要有三条:

  1. 清理项目中CoreData代码
  2. 支持清晰、简单、一行式的查询操作
  3. 当需要优化请求时,可以获取NSFetchRequest进行修改

添加MagicalRecord到项目中

MagicalRecord添加到项目中,和使用其他第三方一样,可以通过下载源码和CocoaPods两种方式添加。

  1. Github下载MagicalRecord源码,将源码直接拖到项目中,后续需要手动更新源码。

  2. 也可以通过CocoaPods安装MagicalRecord,需要在Podfile中加入下面命令,后续只需要通过命令来更新。

pod "MagicalRecord"

在之前创建新项目时,通过勾选"Use Core Data"的方式添加CoreData到项目中,会在AppDelegate文件中生成大量CoreData相关代码。如果是大型项目,被占用的位置是很重要的。而对于MagicalRecord来说,只需要两行代码即可。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 初始化CoreData堆栈,也可以指定初始化某个CoreData堆栈
    [MagicalRecord setupCoreDataStack];
    return YES;
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // 在应用退出时,应该调用cleanUp方法
    [MagicalRecord cleanUp];
}

MagicalRecord是支持CoreData.xcdatamodeld文件的,使得CoreData这一优点可以继续使用。建立数据结构时还是像之前使用CoreData一样,通过.xcdatamodeld文件的方式建立。

模型文件

支持iCloud

CoreData是支持iCloud的,MagicalRecordiCloud相关的操作也做了封装,只需要使用MagicalRecord+iCloud.h类中提供的方法,就可以进行iCloud相关的操作。

例如下面是MagicalRecord+iCloud.h中的一个方法,需要将相关参数传入即可。

+ (void)setupCoreDataStackWithiCloudContainer:(NSString *)containerID localStoreNamed:(NSString *)localStore;

创建上下文

MagicalRecord对上下文的管理和创建也比较全面,下面是MagicalRecord提供的部分创建和获取上下文的代码。因为是给NSManagedObjectContext添加的Category,可以直接用NSManagedObjectContext类调用,使用非常方便。

但是需要注意,虽然系统帮我们管理了上下文对象,对于耗时操作仍然要放在后台线程中处理,并且在主线程中进行UI操作。

+ [NSManagedObjectContext MR_context]  
设置默认的上下文为它的父级上下文,并发类型为NSPrivateQueueConcurrencyType

+ [NSManagedObjectContext MR_newMainQueueContext]  
创建一个新的上下文,并发类型为NSMainQueueConcurrencyType

+ [NSManagedObjectContext MR_newPrivateQueueContext]  
创建一个新的上下文,并发类型为NSPrivateQueueConcurrencyType

+ [NSManagedObjectContext MR_contextWithParent:]  
创建一个新的上下文,允许自定义父级上下文,并发类型为NSPrivateQueueConcurrencyType

+ [NSManagedObjectContext MR_contextWithStoreCoordinator:]  
创建一个新的上下文,并允许自定义持久化存储协调器,并发类型为NSPrivateQueueConcurrencyType

+ [NSManagedObjectContext MR_defaultContext]  
获取默认上下文对象,项目中最基础的上下文对象,并发类型是NSMainQueueConcurrencyType

增删改查

MagicalRecordNSManagedObject添加了一个Category,将增删改查等操作放在这个Category中,使得这些操作可以直接被NSManagedObject类及其子类调用。


  1. 对于托管模型的创建非常简单,不需要像之前还需要进行上下文的操作,现在这都是MagicalRecord帮我们完成的。
// 创建并插入到上下文中
Employee *emp = [Employee MR_createEntity];
// 从上下文中删除当前对象
[emp MR_deleteEntity];
// 获取一个上下文对象
NSManagedObjectContext *defaultContext = [NSManagedObjectContext MR_defaultContext];
    
// 在当前上下文环境中创建一个新的Employee对象
Employee *emp = [Employee MR_createEntityInContext:defaultContext];
emp.name      = @"lxz";
emp.brithday  = [NSDate date];
emp.height    = @1.8;
 
// 保存修改到当前上下文中
[defaultContext MR_saveToPersistentStoreAndWait];
// 执行查找操作,并设置排序条件
 NSArray *empSorted = [Employee MR_findAllSortedBy:@"height" ascending:YES];

自定义NSFetchRequest

下面示例代码中,Employee根据已有的employeeFilter谓词对象,创建了employeeRequest请求对象,并将请求对象做修改后,从MOC中获取请求结果,实现自定义查找条件。

NSPredicate *employeeFilter = [NSPredicate predicateWithFormat:@"name LIKE %@", @"*lxz*"];
NSFetchRequest *employeeRequest = [Employee MR_requestAllWithPredicate:employeeFilter];
employeeRequest.fetchOffset = 10;
employeeRequest.fetchLimit = 10;
NSArray *employees = [Employee MR_executeFetchRequest:employeeRequest];

参数设置

  1. 可以通过修改MR_LOGGING_DISABLED预编译指令的值,控制log打印。
#define MR_LOGGING_DISABLED 1
  1. MagicalRecordDEBUG模式下,对模型文件发生了更改,并且没有创建新的模型文件版本。MagicalRecord默认会将旧的持久化存储删除,创建新的持久化存储。

MagicalRecord中文文档

MagicalRecord的使用方法还有很多,这里只是将一些比较常用的拿出来讲讲,其他就不一一讲解了。在Github上有国人翻译的MagicalRecord官方文档,翻译的非常全面,而且是实时更新的。

这篇文章关于MagicalRecord的部分,也是参考文章来写的,我这里就犯了个懒😓。。。

MagicalRecord中文文档

CoreData优缺点总结

无论是什么东西,肯定不会是绝对完美的,CoreData也是如此。CoreData被设计出来后,对比其他本地持久化方案有自己独有的优势,也有比较严重的问题。

对于一个本地持久化方案的选取,还是要根据公司业务需求,来选择一个适合项目的方案,并没有哪个方案是万能的。

优点

  • 可以设置关联关系,也就是之前讲过的关联属性,关联属性可以和当前对象一起被MOC操作。
    例如Company关联一个Person对象,对Company进行操作时,也可以通过点语法从Company中获取PersonPerson的修改会随着Company一起被持久化。
    如果用SQLite实现起来是很麻烦的,但CoreData可以很容易的完成,这也是CoreData更加面向对象的一种体现。

  • 更加面向对象,将之前Model层的表示和持久化合二为一。把数据库的交互和对象的转换封装起来,使用时不需要接触到任何SQLite相关的代码,直接使用托管对象即可。

  • 开发效率比较快,可以很快的封装一个基于CoreData实现的Model层,而不需要太多的代码就可以实现。

  • 可以很好的防范SQL注入的问题。对于SQLite来说,如果是用FMDB并且用?占位符,也可以防范SQL注入的问题。

  • 可视化化效果好且结构清晰。将模型文件内部的结构,以及实体之间的对应关系等,以可视化的结构展现出来。

  • OC原生编程支持非常好,支持keyPath操作方式。例如设置NSPredicate查找条件时,可以使用keyPath的点语法设置属性。而其他持久化存储对于这点支持的不太好,需要编写很复杂的查找条件,看起来也不太好理解。
    毕竟是Apple自家推出的,所以对OC融合度比较高,可以很好的配合和使用OC对象。

  • 设置一对一或一对多的关系,设置关系后做存储和查询也非常方便,这是非常便于开发的。如果对于性能没有苛刻的要求,并且持久化对象之间关系比较复杂,比较推荐使用CoreData

缺点

  • 灵活性不如SQLiteCoreData是对SQLite的一个封装,上层不能直接对数据库进行操作。处理任何数据都要按照CoreData内部的实现逻辑执行,而不能自定义执行逻辑,对执行逻辑没有可控性。

  • 进行大量数据处理时比较吃力,性能明显低于直接操作SQLite数据库,而且内存占用非常大,需要手动做内存控制。
    当执行一个操作时涉及的数据比较多,需要将所有相关的托管对象加载到内存中,而且中间还涉及到对象的转换等操作。这样对性能和内存的消耗都是非常大的,和涉及到的数据量成正比。

  • 因为CoreData底层是用SQLite实现的,可以在CoreData的基础上,直接编写SQL语句对数据库进行操作。但是并不推荐这样做,在一个项目中应该只有一种持久化的主体方案。而且如果这两种方式混用的话,对于后期维护是非常困难的。
    如果出现这样的需求,最好直接去用SQLite。

  • CoreData入门门槛比较高,很难很好的掌握。
    很多人都说CoreData不好用,这个原因很大一部分都是因为使用方式的问题。CoreData框架学习难度比较大,导致很多人都只是简单的使用CoreData,这些用法很多都是不合理的,很多的高级用法并没有用到。

写在最后

到目前为止CoreData系列的六篇文章就都写完了,文章中可能存在一些没有注意的问题,还请各位提出。博客中包括CoreData在内的所有文章永久更新维护,会不断将新知识添加到对应的文章中,也会对落后的文章进行重写。

在第一篇文章中也说到,我接触CoreData时间也不是很长,这系列文章更像是我学习的一个总结。但是我确实是很认真的在写,文章内容也是检查了很多遍,防止错字或者语法问题。知识点总结的还是比较全面的,在后续我还会更深入的学习CoreData,也可能会推出后续文章。

许多人对于CoreData有很多意见,认为CoreData有各种各样的问题,这并不是空穴来风。在我学习CoreData的过程中,也发现CoreData确实存在诸多问题,例如查询性能略差、灵活性等。所以在使用CoreData的时候,还是根据公司业务需求来权衡是否使用CoreData

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

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

Demo地址:刘小壮的Github


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

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

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

推荐阅读更多精彩内容