我目前正在学习如何在多线程环境中使用核心数据;
因此,我创建了一个包含两个NSManagedObjectContext
的小项目:一个NSManagedObjectContext
主NSMainQueueConcurrencyType
用于读取,其子NSManagedObjectContext
用NSPrivateQueueConcurrencyType
用于创建/更新/删除操作。
经常有人说NSManagedObjectContext
与NSPrivateQueueConcurrencyType
一起保存应该通过performBlock:
完成,如下所示:
[context performBlock:^
{
Book *mutableBook = [self getMutableVersionOfBook:book];
[context deleteObject:mutableBook];
[context save:nil];
}];
如果省略performBlock:
会发生什么情况,如下所示:
Book *mutableBook = [self getMutableVersionOfBook:book];
[context deleteObject:mutableBook];
[context save:nil];
保存是否发生在调用save的线程上?如果不使用performBlock:
会发生什么?
答案 0 :(得分:4)
私人队列MOC只能通过-performBlock:
或-performBlockAndWait:
触及。如果您以任何其他方式触摸它,那么您违反了Core Data的线程边界规则,最终会导致数据损坏。
在某些情况下,这会导致应用程序崩溃,因为违反该线程边界是应用程序级错误。 Apple已经多次关闭了这次崩溃,现在可能是也可能不是崩溃状态。在我看来,它应该一直处于崩溃状态。
作为一般规则,我建议您使用线程限制的MOC作为主MOC的子级而不是使用私有MOC。虽然私有MOC很好用,但每个操作的结构必须在一个块中,并且您无法访问生成的NSManagedObject
实例,除非这些块有限制。最好将操作分离到一个队列中,在该队列中创建一个线程限制的MOC,然后使用比不断深入到块中更清晰的代码(或者更糟糕的是创建巨大的不可维护的块)。
最后。您正在将nil
传递给-save:
。 从不这样做。当你这样做时,你隐藏了一个潜在的问题。即使“这只是一个例子”,这是一个可怕的习惯,你应该立即打破它。即使在示例代码中,传入NSError
并检查错误。即使您只是将结果传递给NSLog
,您至少也会避免意外。
答案 1 :(得分:1)
保存可能会在调用它的线程上发生。有什么后果?我们不知道实现,所以我们只能猜测。有时管理上下文和托管对象的错误使用可能导致一种非常奇怪的行为,你甚至不会认为那是因为线程错误。
上下文和托管对象的所有工作必须在创建它们的线程或队列上完成。基本上,对于传统上下文和具有私有队列并发类型的上下文,它是相同的。后者只是为你创建队列,并始终保持它们。