Nic*_*son 61 cocoa multithreading core-data objective-c
似乎在11月,Apple更新了NSManagedObjectContext类参考和核心数据编程指南文档,明确地将串行GCD调度队列和NSOperationQueues作为可接受的机制来同步访问NSManagedObjectContext.但他们的建议似乎含糊不清,可能相互矛盾,我想确保我已经理解它.
以前,公认的智慧似乎NSManagedObjectContext只能从创建它的线程访问,并且使用串行队列进行同步是不够的; 虽然串行队列一次只执行一个操作,但这些操作可能会在不同的线程上进行调度,而MOC不喜欢这样.
但是现在,从编程指南,我们有:
您可以使用线程,串行操作队列或调度队列进行并发.为了简明起见,本文始终使用"线程"来指代其中任何一个.
到目前为止,这么好(尽管他们对线程和队列的混淆是无益的).所以我可以安全地使用每个(串行)队列的单个上下文,而不是每个操作/块一个,对吧?Apple甚至在Core Data WWDC会话中对此进行了直观描述.
但是......你在哪里为队列创建上下文?在NSManagedObjectContext文档中,Apple声明:
[上下文]假定默认所有者是分配它的线程或队列 - 这由调用其init方法的线程确定.因此,您不应该在一个线程上初始化上下文,然后将其传递给另一个线程.
所以现在我们有了一个NSManagedObjectContext需要知道它的主人是谁的想法.我假设这意味着要在队列中执行的第一个操作应该创建MOC并保存对它的引用以供剩余的操作使用.
这是正确的吗?我犹豫不决的唯一原因是NSManagedObjectContext文章继续说:
相反,您应该传递对持久性存储协调器的引用,并让接收线程/队列创建从该派生协调器派生的新上下文.如果使用NSOperation,则必须在main(对于串行队列)或start(对于并发队列)中创建上下文.
Apple现在似乎将操作与安排执行的队列混为一谈.这是我的头脑,并让我想知道他们是否真的希望你只为每个操作创建一个新的MOC.我错过了什么?
小智 64
NSManagedObjectContext和与之关联的任何托管对象应固定到单个actor(线程,序列化队列,NSOperationQueue,max concurrency = 1).
这种模式称为线程限制或隔离.没有一个很好的短语(thread || serialized queue || NSOperationQueue with max concurrency = 1)所以文档继续说"我们只是在我们的意思是对核心数据doc的其余部分使用'thread'获得序列化控制流程的3种方法中的任何一种"
如果在一个线程上创建MOC,然后在另一个线程上使用它,则通过将MOC对象引用暴露给两个线程来违反线程限制.简单.不要这样做.不要越过溪流.
我们召唤出的NSOperation明确,因为不同的线程和GCD,它有这个奇怪的问题,即-init运行的线程创建的NSOperation上,但 - 主运行的NSOperation的线程上运行.如果你眯着眼睛看它是有道理的,但它不直观.如果你在 - [NSOperation init]中创建你的MOC,那么NSOperation将有助于违反线程限制,直到你的-main方法运行并且你已经被软化了.
我们主动阻止/弃用使用MOC和线程的任何其他方式.虽然理论上可以做bbum提到的事情,但没有人能做到这一点.每个人都绊倒了,忘记了在一个地方打电话给-lock,"init在哪里跑?",或以其他方式超越自己.随着自动释放池和应用程序事件循环和撤消管理和可可绑定和国际志愿者组织目前只有这么多的方法对一个线程扶住一个参照MOC你试过到其他地方传递后.在开始调试之前,它甚至比高级Cocoa开发人员想象的要困难得多.所以这不是一个非常有用的API.
文档更改为澄清并强调线程限制模式是唯一理智的方式.你应该考虑使用-lock和-unlock对NSManagedObjectContext进行额外的尝试,以便(a)不可能,(b)事实上已弃用.它并没有被弃用,因为代码的工作原理与以前一样好.但是使用它的代码是错误的.
有些人在1个线程上创建了MOC,并在没有调用-lock的情况下将它们传递给另一个线程.那从来都不合法.创建MOC的线程始终是MOC的默认所有者.对于在主线程上创建的MOC,这成为更常见的问题.主线程MOC与应用程序的主事件循环交互,以进行撤消,内存管理和其他一些原因.在10.6和iOS 3上,MOC采用主线程所拥有的更积极的优势.
尽管队列未绑定到特定线程,但如果在队列的上下文中创建MOC,则会发生正确的事情.您的义务是遵循公共API.
如果队列是序列化的,则可以与在该队列上运行的后续块共享MOC.
因此,在任何情况下都不要将NSManagedObjectContext*暴露给多个线程(actor等).有一个含糊不清的地方.您可以将NSNotification*从didSave通知传递到另一个线程的MOC的-mergeChangesFromContextDidSaveNotification:方法.
Lil*_*ard 11
听起来你说得对.如果您正在使用线程,那么需要上下文的线程需要创建它.如果您正在使用队列,那么需要上下文的队列应该创建它,很可能是在队列上执行的第一个块.这听起来像唯一令人困惑的部分是关于NSOperations的一点点.我认为NSOperations的混乱并不能保证它们运行的底层线程/队列,因此即使它们都在同一个NSOperationQueue上运行,在操作之间共享MOC也可能不安全.另一种解释是它只是令人困惑的文档.
把它们加起来:
编辑:根据bbum,唯一真正的要求是访问需要序列化.这意味着只要操作全部添加到同一队列,您就可以跨NSOperations共享MOC,并且队列不允许并发操作.
| 归档时间: |
|
| 查看次数: |
7364 次 |
| 最近记录: |