首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >当他们说一个NSManagedObjectContext属于创建它的线程或队列时,苹果是什么意思?

当他们说一个NSManagedObjectContext属于创建它的线程或队列时,苹果是什么意思?
EN

Stack Overflow用户
提问于 2011-01-26 10:21:53
回答 2查看 7.5K关注 0票数 61

似乎在11月,苹果更新了NSManagedObjectContext Class ReferenceCore Data Programming Guide文档,明确支持串行GCD Dispatch Queue和NSOperationQueues作为同步访问NSManagedObjectContext的可接受机制。但他们的建议似乎模棱两可,而且可能自相矛盾,我想确保我正确地理解了它。

以前公认的观点似乎是,NSManagedObjectContext只能从创建它的线程访问,使用串行队列进行同步是不够的;尽管串行队列一次只能执行一个操作,但这些操作可能会被调度到不同的线程上,而MOC不喜欢这样。

但是现在,在编程指南中,我们有:

您可以使用线程、串行操作队列或调度队列来实现并发。为简洁起见,本文通篇使用“线程”来指代其中的任何一个。

到目前为止,一切都很好(尽管它们将线程和队列混合在一起是没有帮助的)。因此,我可以安全地使用每个(串行)队列的单个上下文,而不是每个操作/块一个上下文,对吗?Apple甚至在核心数据WWDC会议上对此进行了可视化描述。

但是..。在哪里创建队列的上下文?在NSManagedObjectContext文档中,苹果声明:

上下文假设默认所有者是分配它的线程或队列-这是由调用其init方法的线程确定的。因此,您不应该在一个线程上初始化上下文,然后将其传递给另一个线程。

所以现在我们有了一个想法,NSManagedObjectContext需要知道它的所有者是谁。我假设这意味着要在队列中执行的第一个操作应该创建MOC并保存对它的引用,以供其余操作使用。

是这样的吗?我犹豫不决的唯一原因是NSManagedObjectContext的文章接着说:

相反,您应该将引用传递给持久存储协调器,并让接收线程/队列创建从该引用派生的新上下文。如果使用NSOperation,则必须在main (用于串行队列)或start (用于并发队列)中创建上下文。

苹果现在似乎将操作与调度其执行的队列混为一谈。这让我头疼,让我怀疑他们到底是不是真的想让你为每个操作创建一个新的MOC。我遗漏了什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-01-27 11:48:05

应该将NSManagedObjectContext和与其关联的任何托管对象固定到单个执行元(线程、序列化队列、最大并发=1的NSOperationQueue )。

这种模式称为线程限制或隔离。(thread || serialized queue || NSOperationQueue with max concurrency = 1)没有一个很好的短语,所以文档继续说“当我们指的是获得序列化控制流的三种方法中的任何一种时,我们将只对核心数据文档的其余部分使用‘线程’”。

如果您在一个线程上创建一个MOC,然后在另一个线程上使用它,那么您就违反了线程限制,将MOC对象引用暴露给了两个线程。很简单。不要这样做。不要过河。

我们显式地调用NSOperation,因为与线程& GCD不同,它有一个奇怪的问题,即-init在创建NSOperation的线程上运行,而-main在运行NSOperation的线程上运行。如果你正确地斜视它,这是有意义的,但它不是直观的。如果你在-NSOperation init中创建MOC,那么在你的-main方法运行之前,NSOperation就会很有帮助地违反线程限制,这样你就完蛋了。

我们积极不鼓励/不赞成以任何其他方式使用MOC和线程。虽然理论上可以做bbum提到的事情,但从来没有人做对过。每个人都犯了错,在一个地方忘记了对-lock的必要调用,"init在哪里运行?",或者以其他方式超越了自己。有了自动释放池、应用程序事件循环、撤销管理器、可可绑定和KVO,一个线程在您尝试将其传递到其他地方后,有很多方法可以保持对MOC的引用。这比高级Cocoa开发人员在开始调试之前想象的要困难得多。所以这不是一个非常有用的API。

文档进行了更改,以澄清并强调线程限制模式是唯一合理的方法。您应该考虑尝试在NSManagedObjectContext上使用-lock和-unlock,这(a)是不可能的,(b)事实上已被弃用。它并不是字面上被弃用的,因为它的代码工作得和以前一样好。但是你使用它的代码是错误的。

有些人在一个线程上创建MOC,并在没有调用-lock的情况下将它们传递给另一个线程。这从来都不合法。创建MOC的线程始终是MOC的默认所有者。对于在主线程上创建的MOC来说,这是一个更常见的问题。由于撤消、内存管理和其他一些原因,主线程MOC与应用程序的主事件循环进行交互。在10.6和iOS 3上,MOC更积极地利用主线程拥有的优势。

尽管队列没有绑定到特定的线程,但是如果您在队列的上下文中创建一个MOC,正确的事情将会发生。您的职责是遵循公共API。

如果该队列是序列化的,则可以与该队列上运行的后续块共享MOC。

因此,在任何情况下,都不要将NSManagedObjectContext*公开给多个线程(执行元等)。有一点是不明确的。您可以将NSNotification*从didSave通知传递给另一个线程的MOC的-mergeChangesFromContextDidSaveNotification:方法。

  • Ben
票数 64
EN

Stack Overflow用户

发布于 2011-01-26 10:28:46

听起来你是对的。如果你使用线程,需要上下文的线程需要创建它。如果您正在使用队列,那么需要上下文的队列应该创建它,很可能是作为在队列上执行的第一个块。听起来唯一令人困惑的部分是关于NSOperations的部分。我认为混淆之处在于NSOperations不能保证它们在哪个底层线程/队列上运行,所以即使它们都在同一个NSOperationQueue上运行,在操作之间共享一个MOC也可能是不安全的。另一种解释是,它只是混淆了文档。

总结一下:

  • 如果你使用线程,在想要它的线程上创建MOC
  • 如果你使用GCD,在你的串行队列
  • 上执行的第一个块中创建MOC如果你使用NSOperation,在NSOperation内部创建MOC并且不要在操作之间共享它。这可能有点偏执,但NSOperation不能保证它在哪个底层线程/队列上运行。

编辑:根据bbum的说法,唯一真正的需求是访问需要序列化。这意味着您可以跨NSOperations共享一个MOC,只要所有操作都添加到同一个队列中,并且该队列不允许并发操作。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4800889

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档