文档章节

coreData 深入理解4 --总结 (线程安全与同步--iOS5 前后对比)

andyhe91
 andyhe91
发布于 2015/04/24 16:16
字数 971
阅读 707
收藏 3

分类: Base&Inter&Skill iphone 平台 iphone+平台2014-03-24 15:27 1140人阅读 评论(1) 收藏 举报

目录(?)[+]

Core Data是iOS中很重要的一个部分,可以理解为基于SQLite(当然也可以是其他的Storage,如In-memory,只是SQLite比较常见)的一个ORM实现,所以有关系数据库的特性,又不用写SQL。顺便吐一下槽,官方说法是使用Core Data能减少50%-70%的代码量,但相信用过的人应该都心里明白,Core Data使用起来还是比较麻烦的,这也是为什么有不少的第三方类库来代替/二次包装Core Data。

稍微复杂的应用就有可能出现同时处理多份数据的情况,这就需要用到多线程Core Data。在 iOS 5之前,官方推荐的是使用「Thread Confinement」,就是每个线程使用独立的MOC(managed object context),然后共享一个PSC(persistent store coordinator)。同时在线程之间传递数据时,要传递objectID,而不是object,因为前者是线程安全的,后者不是。

如果A线程里,对PSC执行了CUD(create, update, delete)操作,其他线程如何感知呢?这就需要通过监听事件来实现。比如在线程A中监听「NSManagedObjectContextDidSaveNotification」事件,如果线程B中执行了CUD操作,线程A就能感知到,并触发响应的action,虽然可以通过noti userinfo来获取managed objects,但因为它们是关联到另一个MOC,所以无法直接操作它们,解决方法就是调用「mergeChangesFromContextDidSaveNotification:」方法。

用一张图来形容的话,大体就是这样:

iOS multi thread Core Data before iOS 5

- (void)_setupCoreDataStack{
     // setup managed object model
     NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Database" withExtension:@"momd"];
     _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
 
     // setup persistent store coordinator
     NSURL *storeURL = [NSURL fileURLWithPath:[[NSString cachesPath] stringByAppendingPathComponent:@"Database.db"]];
 
     NSError *error = nil;
     _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_managedObjectModel];
 
     if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
         // handle error
   }
 
     // create MOC
     _managedObjectContext = [[NSManagedObjectContext alloc] init];
     [_managedObjectContext setPersistentStoreCoordinator:_persistentStoreCoordinator];
 
     // subscribe to change notifications
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_mocDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:nil];}

再来看看Notification Handler,主要作用就是合并新的变化。

- (void)_mocDidSaveNotification:(NSNotification *)notification{
     NSManagedObjectContext *savedContext = [notification object];
 
     // ignore change notifications for the main MOC
     if (_managedObjectContext == savedContext) {
          return;
     }
 
     dispatch_sync(dispatch_get_main_queue(), ^{
      [_managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
     });}

这种方式实现起来和维护起来都有点麻烦,所以iOS 5中就出现了更加方便和灵活的实现,也就是「Nested MOC」。

[[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

可以看到在初始化时可以选择ConcurrencyType,可选的有3个:

NSConfinementConcurrencyType

这个是默认项,每个线程一个独立的Context,主要是为了兼容之前的设计。

NSPrivateQueueConcurrencyType

创建一个private queue(使用GCD),这样就不会阻塞主线程。

NSMainQueueConcurrencyType

创建一个main queue,使用主线程,会阻塞。

还有一个重要的变化是MOC可以指定parent。有了parent后,CUD操作会冒泡到parent。一个parent可以有多个child。parent还可以有parent。

因为UI相关的数据必须在主线程获取,同时又要避免数据库的I/O操作阻塞主线程,所以就有了下面这个模型:

multi thread ios 5 nested MOC

我对这种实现方式的一个困惑是:child无法得知parent的变化,也就是说,如果NSFetchedResultsController绑定了Main MOC,当Background Write MOC save时,NSFetchedResultsController为何能知晓?求指点。

这种方式比「Thread Confinement」稍微简单了点,也更明了。不过个人还是推荐使用MagicalRecord,因为实现起来更加简单,等有空再写一篇。

写了一个使用了这个模型的demo,配合TableView和NSFetchedResultsController,有兴趣的可以看下:https://github.com/limboy/coredata-with-tableview

2013/06/17更新

之前的困惑已消除,NSFetchedResultsController跟PSC无关,只要绑定的MOC有了save动作,NSFetchedResultsController就会收到通知,无论这个save操作有没有写入到持久层。


© 著作权归作者所有

共有 人打赏支持
andyhe91
粉丝 58
博文 129
码字总数 209109
作品 0
长沙
私信 提问
iOS 底层以及数据问题深入研究(1)

几周前有人问了我几个问题,我觉得自己能回答出来,但是深入的时候才发现自己还是浮在水表明,没有真正的去理解。所以将理解后易忽略的问题总结并记录下来 1 RunLoop --关于NStimer添加到NSR...

李周
2017/08/26
0
0
读《深入理解Java虚拟机》- 笔记08

《深入理解Java虚拟机:JVM高级特性与最佳实践》第2版 第10章 早期(编译期)优化 59. 语法糖 在计算机语言中添加某种语法,对语言的功能没有影响,但是方便开发人员使用。 泛型是一种语法糖...

阿历Ali
2018/08/18
0
0
objective-c设计模式之---单例

单例模式可以说是每个应用都有用到的一个模式,在iOS的世界里更是常见。例如我们的UIApplication sharedApplicaiton应用的就是单利模式, defaultManager和defaultCenter等也是常见的单利。这...

Megan_zhou
2013/07/22
0
2
跳槽时,这些Java面试题99%会被问到

我在 Oracle 已经工作了近 7 年,面试过从初级到非常资深的Java工程师,且由于 Java 组工作任务的特点,我非常注重面试者的计算机科学基础和编程语言的理解深度,可以不要求面试者非要精通 ...

Java小铺
2018/08/15
0
0
10《Java核心技术》之如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全?

一、提出问题 之前我们一起讨论过两讲 Java 集合框架的典型容器类,它们绝大部分都不是线程安全的,仅有的线程安全实现,比如 Vector、Stack,在性能方面也远不尽如人意。幸好 Java 语言提供...

飞鱼说编程
2018/10/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Android Messenger进程间客户端向服务端传递数据

Messenger:客户端向服务端传递数据 1.Service: public class MessengerService extends Service { private Messenger messenger = new Messenger(new Handler() { public void handleMess......

Coding缘
16分钟前
0
0
Pod在多可用区worker节点上的高可用部署

一、 需求分析 当前kubernetes集群中的worker节点可以支持添加多可用区中的ECS,这种部署方式的目的是可以让一个应用的多个pod(至少两个)能够分布在不同的可用区,起码不能分布在同一个可用...

zhaowei121
35分钟前
2
0
oracle XTTS介绍

一、什么是XTTS 首先什么是XTTS。XTTS其实是从TTS来的,TTS其实也是传输数据的一种手段,传输数据的时候可能用过EXP的方式,再往后可能用数据泵导入导出一些数据,或者去做备份然后再恢复。其...

突突突酱
35分钟前
0
0
[缺陷分析]半同步下多从库复制异常

引 言 本文是由爱可生研发团队出品的「图解MySQL」系列文章,不定期更新,但篇篇精品。 爱可生开源社区持续运营维护的小目标: 每周至少推送一篇高质量技术文章 每月研发团队发布开源组件新版...

爱可生
35分钟前
0
0
二维数组序号重置

public static function unique_arr($array2D,$stkeep=false,$ndformat=true){ // 判断是否保留一级数组键 (一级数组键可以为非数字) if($stkeep) $stArr = array_keys($array2D); // 判断是......

dragon_tech
38分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部