一个典型的设置:我们有一个带有 a 的主线程mainMOC
和一个带有自己的backgroundMOC
. backgroundMOC
后台线程通过将块分派到对 执行只读操作backgroundQueue
。
backgroundMOC
需要合并来自的更改,因此mainMOC
我们注册NSManagedObjectContextDidSaveNotification
然后执行类似的操作
- (void)mainMocDidSave:(NSNotification *)notification {
dispatch_async(backgroundQueue, ^{
[backgroundMoc mergeChangesFromContextDidSaveNotification:notification];
});
}
假设用户删除了mainMOC
. 上面的代码对我来说似乎并不安全,因为合并将在未来的某个时候完成。在合并完成之前,可能仍然存在backgroundQueue
试图使用已删除对象的块。
显而易见的解决方案是dispatch_sync
改用(或performBlockAndWait
, performSelector:OnThread:...
)。从我在互联网上看到的代码片段来看,这似乎是每个人都在做的事情。但我也不喜欢这个解决方案。
该名称NSManagedObjectContextDidSaveNotification
暗示在发送通知时保存已经发生。所以相应的行已经从底层数据库中删除(假设是一个 sqlite 存储)。dispatch_sync
必须等待队列中的其他块完成才能合并更改,并且这些其他块仍然可以尝试使用已删除的对象,从而导致NSObjectInaccessibleException
.
在我看来,将更改从一个线程/队列合并到另一个的正确方法是
- 订阅
NSManagedObjectContextWillSaveNotification
并NSManagedObjectContextDidSaveNotification
在后台线程上。 - On
NSManagedObjectContextWillSaveNotification
:清空backgroundQueue
并暂停任何将新块分派到队列的操作。 - On
NSManagedObjectContextDidSaveNotification
:同步合并更改。 - 在后台队列上恢复正常操作。
这是正确的方法还是我错过了什么?