私は Marcus Zarra の Core Data ブックのマルチスレッドに関する章を読み、彼のサンプル コードをかなり詳しく調べました。しかし、彼のコードや他の場所で見つけた他のコードは、お互いを認識する必要のないバックグラウンド プロセスに焦点を当てているようです。これらの例は、ツリー構造のインポートには適していますが、有向非巡回グラフのような、より一般的な (複雑な) 構造のインポートには対応していません。
私の場合、C++ クラス階層を解析しようとしており、できるだけ多くの NSOperations を使用したいと考えています。遭遇したクラスごとに NSManagedObject インスタンスを作成し、保存されるたびに異なる NSManagedObjectContexts をマージしたいと考えています。
余談ですが、ファイルを繰り返し処理し、一度に 1 つずつ解析する単一の NSOperation で動作させることができます。この実装では、メイン スレッドの MOC で -mergeChangesFromContextDidSaveNotification: を呼び出す -mergeChanges: アプローチがうまく機能します。
しかし、理想的には、1 つの NSOperation でソース ファイルを反復処理し、NSOperations を生成して各ファイルを解析します。私はいくつかのアプローチを試みましたが、うまくいかないようです。最も有望なのは、各 NSOperation が NSManagedObjectContextDidSaveNotification を監視するようにすることでした。-mergeChanges: を使用すると、次のようになります。
- (void) mergeChanges:(NSNotification *)notification
{
// If locally originated, then trigger main thread to merge.
if ([notification object] == [self managedObjectContext])
{
AppDelegate *appDelegate = (AppDelegate*)[[NSApplication sharedApplication] delegate];
NSManagedObjectContext *mainContext = [appDelegate managedObjectContext];
// Merge changes into the main context on the main thread
[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
withObject:notification
waitUntilDone:YES];
return;
}
// If not locally originated, then flag need to merge with in this NSOperation's thread.
[self setNeedsToMerge:YES];
[self setMergeNotification:notification];
}
基本的に、解析中の NSOperation の main() は ivar 'needsToMerge' を定期的にチェックしていました。true の場合、-mergeChangesFromContextDidSaveNotification: は、キャッシュされた NSNotifications を使用してローカル MOC で呼び出されました。そして、needsToMerge がリセットされました。通知がローカルで発生した場合、メイン スレッドはその MOC で -mergeChangesFromContextDidSaveNotification: を実行するように指示されました。
これが機能しなかった理由と、これが得られた理由があると確信しています。
警告: 呼び出しをキャンセルしています - 現在のスレッドのスタック上の objc コードにより、これは安全ではなくなります。
また、NSPeristentStoreCoordinator のロックを使用してアクセスを制御しようとしましたが、NSManagedObjectContext の -save: メソッドの呼び出し中にロックが保持されると問題が発生します。なぜなら、-save: は関心のあるオブザーバーに保存イベントを通知し、-mergeChangesFromContextDidSaveNotification: の取得をブロックしているように見えるからです。 PSCのロック。
これはずっと簡単なはずです。