Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 当他们说NSManagedObjectContext由创建它的线程或队列拥有时,Apple是什么意思?_Objective C_Multithreading_Cocoa_Core Data - Fatal编程技术网

Objective c 当他们说NSManagedObjectContext由创建它的线程或队列拥有时,Apple是什么意思?

Objective c 当他们说NSManagedObjectContext由创建它的线程或队列拥有时,Apple是什么意思?,objective-c,multithreading,cocoa,core-data,Objective C,Multithreading,Cocoa,Core Data,似乎在11月,苹果公司更新了和文档,明确允许串行GCD调度队列和NSOperationQueues作为同步访问NSManagedObjectContext的可接受机制。但他们的建议似乎模棱两可,可能相互矛盾,我想确保我已经正确理解了 以前公认的智慧似乎是,只能从创建它的线程访问NSManagedObjectContext,使用串行队列进行同步是不够的;虽然串行队列一次只执行一个操作,但这些操作可能会安排在不同的线程上,MOC不喜欢这样 但现在,从编程指南中,我们有: 您可以使用线程、串行操作队列

似乎在11月,苹果公司更新了和文档,明确允许串行GCD调度队列和NSOperationQueues作为同步访问
NSManagedObjectContext
的可接受机制。但他们的建议似乎模棱两可,可能相互矛盾,我想确保我已经正确理解了

以前公认的智慧似乎是,只能从创建它的线程访问
NSManagedObjectContext
,使用串行队列进行同步是不够的;虽然串行队列一次只执行一个操作,但这些操作可能会安排在不同的线程上,MOC不喜欢这样

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

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

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

但是。。。在哪里为队列创建上下文?在
NSManagedObjectContext
文档中,Apple声明:

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

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

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

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


苹果现在似乎将操作和调度其执行的队列混为一谈。这让我很惊讶,我想知道他们是否真的希望你为每一个操作创建一个新的主运行中心。我错过了什么?

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

总而言之:

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

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

NSManagedObjectContext及其关联的任何托管对象应固定到单个参与者(线程、序列化队列、NSOperationQueue with max concurrency=1)

这种模式称为线程限制或隔离。对于(线程| |序列化队列| | | NSOperationQueue with max concurrency=1)没有一个很好的短语,因此文档接着说“我们将仅对核心数据文档的其余部分使用‘线程’,而我们指的是获得序列化控制流的三种方法中的任何一种”

如果在一个线程上创建MOC,然后在另一个线程上使用它,则通过将MOC对象引用公开给两个线程,违反了线程限制。简单。不要这样做。不要越过小溪

我们显式地调用NSOperation,因为与threads&GCD不同,它有一个奇怪的问题,即-init在创建NSOperation的线程上运行,而-main在运行NSOperation的线程上运行。如果你正确地斜视它,它是有意义的,但它不是直观的。如果您在-[NSOperation init]中创建了MOC,那么在-main方法运行之前,NSOperation将有助于违反线程限制,从而使您受到限制

我们积极劝阻/反对以任何其他方式使用MOC和线程。虽然理论上可以做到bbum所提到的,但没有人能做到这一点。每个人都犯了错误,忘记了在一个地方调用-lock,“init runs where?”,否则他们自己就聪明了。通过自动释放池、应用程序事件循环、撤消管理器、cocoa绑定和KVO,在您尝试将MOC的引用传递到其他地方之后,一个线程可以通过多种方式保持对MOC的引用。在高级Cocoa开发人员开始调试之前,这远比他们想象的困难。所以这不是一个非常有用的API

文档更改为澄清并强调线程限制模式是唯一明智的选择。你应该考虑尝试在NSMARKEDIT对象上下文中锁定和解锁是不可能的,并且(b)事实上