場所のリストを表示する必要があり、3 つのスレッドで実行されるアプリがあるとします。
- メインスレッド
- Main Thread Background Sync (場所をサーバーと同期するため)
- ジオコーディング スレッド (バックグラウンドで場所をジオコーディングするため)
私が専用にした3つのスレッドすべてでNSManagedObjectContexts
(MOC)。各 MOC が基礎となるデータを変更できる場合 (たとえば、メイン スレッドは場所をお気に入りに追加でき、バックグラウンド同期は場所の名前を変更でき、ジオコーディング スレッドは緯度/経度情報を追加できます)、アプリはNSManagedObjectContextDidSaveNotification
それぞれに登録する必要があります。スレッドをmergeChangesFromContextDidSaveNotification
作成し、1 つの MOC が保存された場合 (メイン スレッドの MOC にマージするだけでなく)、他のスレッド内の対応する他の MOC に展開します。
今、私はそれをやっていますが、それは正しくないと感じています:(
現在実行中のスレッドを MOC とともに保存するために使用する辞書があります。MOC の 1 つがポップするたびに、NSManagedObjectContextDidSaveNotification
この配列を I ループし、mergeChangesFromContextDidSaveNotification
他のすべての MOC/スレッドに送信します。もちろん、NSThreadWillExitNotification
スレッドの 1 つがなくなったときに配列から Thread/MOC を削除できるように、オブザーバーも追加しました。ディクショナリのすべての追加/削除アクションはロックされています。そして、それが私が今ちょっと立ち往生しているところです。たまに電話すると
[moc performSelector:@selector(mergeChangesFromContextDidSaveNotification:)
onThread:thread
withObject:notification
waitUntilDone:YES];
MOC/スレッド ディクショナリをループすると、次の例外がスローされます。
[NSManagedObjectContext performSelector:onThread:withObject:waitUntilDone:modes:]: target thread exited while waiting for the perform
どうやら、これは競合状態が原因です。ディクショナリをループしている間 (オブジェクト配列の抽出中にロックしただけです)、スレッド内の 1 つが終了するため、参照が無効になります。ただし、ループ全体の前に辞書ロックを配置すると、デッドロックが発生します。
[moc performSelector:@selector(mergeChangesFromContextDidSaveNotification:)
onThread:thread
withObject:notification
waitUntilDone:YES];
場合によってはループ内で永遠に時間がかかるため(理由はまだわかりません)、アプリ全体が停止します。waitUntilDone:NO
この場合、呼び出しを行うのは安全ですか? それで治りそうだから。これでパンドラの箱を誤って開けてしまったら…。
よろしく、
セバスチャン