要約:[myMOC mergeChangesFromContextDidSaveNotification:notification]
マルチスレッド シナリオで呼び出すと、アプリがハングします。
詳細な状況は次のとおりです。
私のアプリはサーバーから大量のデータをダウンロードし、最初の起動時に Core Data に保存します。それはいくつかの部分に分かれています。全体を解析するには数秒かかり、その時間のほとんどは 2 つのチャンクに費やされます。高速化するために、これら 2 つのチャンクを並列化しました。これは次のようになります。
NSArray *arr = [self parseJsonData:downloadedNSData]; //turns NSData into JSON array
//using NSJSONSerialization
NSMutableArray __block *first = [[NSMutableArray alloc]init];
NSMutableArray __block *second = [[NSMutableArray alloc]init];
//put half of arr in first and half in second with a loop
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dipatch_group_create();
dispatch_group_async(group, queue, ^
{
for (id element in first)
{
[MyDataClass parseData:element]; //create NSManagedObject subclass, save
}
[self saveContext];
});
dispatch_group_async(group, queue, ^
{
for (id element in second)
{
[MyDataClass parseData:element]; //create NSManagedObject subclass, save
}
[self saveContext];
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
[self saveContext]
save
MOC を呼び出します。これはもちろん複数のスレッドで行われるManagedObjectContext
ため、スレッドごとに個別に作成する必要があります。これは、s へのスレッド名 ( の呼び出し) を維持するこのオブジェクト ( ) のプロパティを介して MOC を公開することによって実現されself
ます。アクセス時に の MOC がない場合は、新しい MOC を作成し、辞書に追加して保存します。各 MOC が作成されると、その変更通知にサブスクライブします。NSMutableDictionary
description
NSThread
NSManagedObjectContext
[NSThread currentThread]
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification object:createdMOC];
ではmergeChanges
、コンテキストの辞書をループして、mergeChangesFromContextDidSaveNotification
これが発生しているスレッドの 1 つを除くすべてのコンテキストを呼び出します。より具体的には、[performSelector:onThread:withObject:waitUntilDone:]
各 MOC が作成されたスレッドでこれを実行するように使用します。
と私の方法NSLock
の両方を使用してロックしています。それらをロックしていなかった場合、「Cocoa error 133020」が表示されました。これは、変更のマージ エラーを意味しているようです。[myMOC save]
mergeChanges
だから、これは私のロギングが私に言っていることです:
- スレッド 1 は保存するためのロックを取得し、保存を開始します
- スレッド 1 でマージ コンテキスト通知が送信されます。スレッド 1 は、変更をマージするためのロックを取得し、そのプロセスを開始します。メイン スレッドの MOC の変更をマージし、バックグラウンド スレッドの MOC の 1 つを実行するとハングします。
- スレッド 2 は保存を開始しますが、保存のためのロックを取得しません。これは、他のスレッドが変更をマージしようとしてスタックしているためです。
では、変更をマージするとハングするのはなぜですか? このシナリオを処理するより良い方法はありますか?
更新:を使用してロックするだけでなく[persistentStoreCoordinator lock]
、通話の周りで使用しようとしましたが、役に立ちませんでした。また、呼び出しの 1 つに呼び出しの前に追加しようとしましたが、役に立ちませんでした。[MOC save]
NSLock
[NSThread sleepForTimeInterval:2]
[self saveContext]
dispatch_group_async
更新 2:おそらくここでのより良い質問は、マージの競合が発生した理由です (Cocoa エラー 133020)。それは期待されていますか?マージを正しく行っていますか (1 つの保存を除くすべてのコンテキストにマージしています)?
更新 3:マルチスレッドの実行方法に関するより大きなコンテキストに対処するために、別の質問を投稿しました。