典型的な設定: を持つメイン スレッドと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
: 変更を同期的にマージします。 - バックグラウンド キューで通常の操作を再開します。
これは正しいアプローチですか、何か不足していますか?