Core Data系列四——多线程设计

1. 线程访问限制

  1. NSManagedObjectContext不允许跨线程操作
  2. NSManagedObject不允许跨线程访问

这两处所说的线程指的NSManagedObjectContext类私有的_dispatchQueue, 我把它叫做MOC的操作线程. MOC还有另外一个私有的_queueOwner, 指的是创建这个MOC的线程,我把它叫做MOC的所属线程。 这两者不是一回事。

本节参见:

  1. https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Conceptual/CoreData/Concurrency.html#//apple_ref/doc/uid/TP40001075-CH24-SW1
  2. https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/index.html#//apple_ref/doc/uid/TP30001182-256616

2. NSManagedObjectContext与多线程相关的说明

MOC有两种类型: 基于线程限制的和基于queue的。

  1. 基于线程限制的MOC,需要保证在MOC的所有操作需要在它的创建线程上。也就是说, 它的操作线程和所属线程为同一个线程。这种类型的MOC是通过-init方法初始化的,且要求它的parent store是PSC。 使用这种基于线程限制的MOC时,需要编程者自己保证仅在它的创建线程上操作它。
  2. 基于queue的MOC,为了保证它的所有操作都在其操作线程上(且其操作线程私有),只需要把操作包装在performBlock:或者performBlockAndWait:中。而这两个方法本身是可以在任意线程中调用的。这种类型的MOC,其操作线程和所属线程一般不是同一个线程(NSMainQueueConcurrencyType类型的是例外)。

以上两种类型的MOC, 其所属线程均为调用它的init方法的线程。

3. 数据同步

当操作线程为A的MOC里的数据有变化时,另一个操作线程为B的MOC如何同步这种变化呢? 两种方案:

  1. 通过监听NSManagedObjectContextDidSaveNotification通知,主动merge
  2. 通过parent/child nested context. 当child context做save操作后,这种变化会自动同步到parent context中。

MagicalRecord是针对Core Data的二次封装,很好的处理了多线程相关的操作。我写的另外一篇文章中简单分析了MagicalRecord的设计,感兴趣的可以阅读一下。
本节参见:

  1. https://forums.pragprog.com/forums/252/topics/12271
  2. http://oleb.net/blog/2014/06/core-data-concurrency-debugging/#fnref:3

4. 常见的多线程设计方案

根据Core Data大神Florin Kugler的介绍,app中常见的多线程设计的方案有一下三种:
方案1:

方案2:

方案3:

从性能上看,这三种方案中第一种方案对主线程的影响最大。因为虽然耗时的数据操作是放在Bg MOC中操作的,但最终持久化到DB中以及从DB中获取数据均需要通过main MOC。第二种方案的设计的性能介于第二种和第三种之间,但各个context之间的数据同步是通过parent context关系自动同步的,比较优雅。第三种方案的性能最优,但context之间是通过通知来进行的,相对比较复杂。 其中第二种方案的性能差于第三种方案,说明自动save的成本还是比主动merge的成本要高的。
具体的性能数据,有兴趣的可以参考Florian大神的两篇post:

  1. http://floriankugler.com/2013/04/02/the-concurrent-core-data-stack/
  2. http://floriankugler.com/blog/2013/4/29/concurrent-core-data-stack-performance-shootout

5. 关于Core Data多线程的debug

iOS 8.0以上,在 Arguments中添加: -com.apple.CoreData.ConcurrencyDebug 1 ,系统便会自动加载CoreData debug版本的库。当违反了多线程操作原则时便会强制crash。
说明:本文为原创内容,转载请注明出处

posted @ 2015-10-30 17:57  敏迪  阅读(325)  评论(0编辑  收藏  举报