GCD调度队列是否足以将Core Data上下文限制在单个线程中

ren*_*ene 15 core-data thread-safety grand-central-dispatch ios

我开始认为我的问题的答案是"不",但我仍然对此感到困惑和不确定.所以请确认.我已经了解了在使用多线程的Core Data时要小心.NSManagedObjectContext对象不得跨越线程边界.作为一个同时具有线程和核心数据的新手,我很高兴地发现GCD应该可以使其中的一些变得更容易.

或许,我想我会简单地创建一个专用的GCD调度队列来处理核心数据(如果需要,甚至可以有多个调度队列,每个队列都有自己的核心数据上下文).那会很简单.

但现在我意识到GCD调度队列的一大优势是它根据需要管理和使用多个线程.所以 - 如果我理解这一点 - 我交给同一个调度队列的任务最终可能会在不同的线程中运行,可能会将核心数据上下文从一个线程切换到另一个线程,并且出现问题.是对的吗?

我已经阅读了许多相关的问题和答案,例如Core Data和threads/Grand Central Dispatch,但我仍然有些困惑.使用GCD队列接受的问题答案确实确保在每个线程上创建新的上下文,但没有指出这样做的必要性.另一个答案是"您可以在名为com.yourcompany.appname.dataaccess的队列上执行所有CoreData工作",这似乎暗示只要Core Data工作仅限于一个GCD调度队列,那么一切正常.也许不是.

Cal*_*leb 20

更新:正如@adib在评论中指出的那样,在iOS 9和MacOS X 10.11中,序列化托管对象上下文访问的方法已经改变.NSConfinementConcurrencyType,线程限制策略现在已被弃用,有利于NSPrivateQueueConcurrencyTypeNSMainQueueConcurrencyType.换句话说,停止使用线程并发访问Core Data对象,而是开始使用GCD.您应该使用主调度队列或与MOC关联的队列,具体取决于您配置MOC的方式,而不是您自己创建的队列.使用NSManagedObject -performBlock:-performBlockAndWait:方法很容易做到这一点.


简短回答:使用串行调度队列可以提供对托管对象上下文的序列化访问,这是实现"线程限制"策略的可接受方式,即使GCD实际上可能使用多个线程.

更长的回答:

使用GCD队列接受的问题答案确实确保在每个线程上创建新的上下文,但没有指出这样做的必要性.

你需要记住的最重要的事情是,你必须避免修改从两个不同的线程管理对象范围内的同时.这可能会使上下文陷入一种不一致的状态,并且没有任何好处.因此,您使用的调度队列类型很重要:并发调度队列将允许多个任务同时进行,如果它们都使用相同的上下文,您将遇到麻烦.另一方面,如果使用串行调度队列,则可能在不同的线程上执行两个或多个任务,但任务将按顺序执行,并且一次只能运行一个任务.这与在同一个线程上运行所有任务非常相似,至少就维护上下文的一致性而言.

请参阅此问题答案以获得更详细的解释.

这就是Core Data一直以来的工作方式.该核心数据并发的核心数据编程指南的部分提供了有关如何,如果你决定使用在多线程一个上下文进行咨询.它主要讨论在您访问它时需要非常小心地锁定上下文.但是,所有锁定的关键是要确保两个或多个线程不会同时尝试使用上下文.使用序列化调度队列实现了相同的目标:因为队列中一次只执行一个任务,所以两个或多个任务不可能同时尝试使用上下文.

  • @SedateAlien,在他回答的早期,Ben指出[文档](http://tinyurl.com/6dlg75j)中的说明:***注意:**您可以使用线程,串行操作队列或发送并发队列.为了简明起见,本文始终使用"线程"来引用其中任何一个."*因此,在他的答案的其余部分或文档中,您可以用*serial dispatch queue*替换*thread*. ,重要的是避免同时为不同的事物使用相同的上下文.所提到的三种机制中的任何一种都可用于实现这一点. (2认同)