Core Data 多线程操作实战篇

最近在解决百度音乐iPhone客户端偶现数据库操作crash的问题,顺手整理了下CoreData的多线程原则,以及实际开发时应该如何遵守这些原则。

Core Data多线程操作的基本原则

  1. 不允许跨线程访问MOC: 在某一个MOC上的CRUD操作只能在它的操作线程上进行
  2. 不允许跨线程访问MO:对MO的操作只能在它所属的MOC的操作线程上进行。需要注意的是,访问一个FRC的fetchedObjects数组也只能在FRC所属的MOC的操作线程上进行

Core Data的新版本

所谓的新版本,其实是从iOS 5.0就开始支持了。新版本的Core Data废弃了confinement context,替代它的是queue context。这两种context的区别在于,使用confinement context必须自己保证CRUD操作只在创建它的线程上执行,也就是说创建这个confinement context的线程就是它的操作线程。 而使用queue context则只需要用-performBlock:或者-performBlockAndWait:方法执行CRUD操作,这些操作都被dispatch到context持有的serial _dispatchQueue上执行。

Magical Record的新版本(coming soon)

根据Magical Record的说明,从3.0版本起,MagicalRecord中的-MR_contextForCurrentThread将被弃用。刚开始我没想清楚其中的原因,后来通过在github上提问,Magical Record的维护者之一tonyarnold给出的原因是:

  1. Core Data已经废弃了confinement context
  2. Core Data中新的queue context内部使用serial dispatch_queue来保证线程安全
  3. MR中的-MR_contextForCurrentThread方法是把一个queue context存储在一个thread的字典里。这样会导致调用这个方法的线程一定不是queue context的操作线程.

我是这么理解的:

  1. 我们使用-MR_contextForCurrentThread这个方法通常的习惯是,拿到这个方法返回的context之后,直接在这个context上进行CRUD操作。这在旧版本使用confinement context的Core Data是没有问题的。因为这个confinement context的创建线程就是它的合法操作线程
  2. 对于queue context, 如果我们继续按照1中的方式使用这个context是有问题。原因就是tonyarnold给出的第三点。正确的做法应该是把CRUD操作都放在-performBlock:-performBlockAndWait:
  3. 我认为,如果我们能用正确的方式使用-MR_contextForCurrentThread方法返回的context, 那么是没有问题的

App中应该如何遵守Core Data的多线程操作原则

如果你App也使用了Magical Record, 那么建议你按照官方说明上的方式替换掉它打算废弃的API。比如用每次创建一个新的-MR_context的方式来替换掉-MR_contextForCurrentThread的使用。

下面是我在修改百度音乐iPhone客户端的数据库操作时总结的几个方法:

  1. 每个入参有MO的方法

    1. 自己保证(不是由调用者保证)对MO的访问和修改在MO.managedObjectContext的操作线程上执行
    2. 此方法应该仅把DB操作放在MO.managedObjectContext的操作线程上。 这么要求是为了避免修改数据库操作之外的任务的线程安排
    3. 注意,不要把FRC.fetchedObjects作为参数传递。对这个数组做遍历、或者取大小等的操作必须要在FRC.managedObjectContext中进行,而仅由传入的FRC.fetchedObjects无法获取此信息
  2. MO的category中的方法

    1. -方法,没有必要用-performBlock:-performBlockAndWait:包起来。因为调用者应该有这样的意识:对MO的操作需要在它所属的MOC上进行。这点和CoreData的要求是一致的
    2. +方法需要自己保证不违反线程操作原则。 这点和MagicalRecord保持一致

Core Data有关的Debug方式

  • -com.apple.CoreData.ConcurrencyDebug 3
  • -com.apple.CoreData.SQLDebug 3
  • -com.apple.CoreData.SyntaxColoredLogging YES
posted @ 2015-12-30 17:13  敏迪  阅读(987)  评论(0编辑  收藏  举报