1

2日後、CoreDataを複数のスレッドで動作させようとしています。NSOperationsで標準のスレッド制限メソッドを試し、通知をマージし、objectWithIdを使用して、スレッドごとのコンテキストのディクショナリを試しましたが、それでも奇妙なデッドロック、不整合の例外、その他の厄介なものがたくさんあります。それは私を夢中にさせています...さらに、両方のスレッドが共有永続ストアに変更を加える可能性がある場合に、2つのスレッドでコンテキストを管理する方法についての単一の例や説明を見つけることができません...

新しいiOS5の方法を使おうとしましたが、それでもエラーが発生します。最初の問題は、コンテキストを保存するときのデッドロックです。私はすべての不要なコードを削除し、このコードを十分に速く実行するとデッドロックが発生します(ボタンをすばやくタップすることによって):

    NSManagedObjectContext *context = [StoreDataRetriever sharedRetriever].managedObjectContext;

    for (int i = 0; i < 5; i++) {            
        NSError *error = nil;
        NSLog(@"Main thread: %@, is main? %d", [NSThread currentThread], [NSThread isMainThread]);
        BOOL saveOK = [context save:&error];

        if (!saveOK) {
            NSLog(@"ERROR!!! SAVING CONTEXT IN MAIN");
        }

        [context performBlock:^{

            NSLog(@"Block thread: %@", [NSThread currentThread]);

            NSError *error = nil;
            BOOL savedOK = NO;

            savedOK = [context save:&error]; 

            if (!savedOK) {
                NSLog(@"ERROR!!! SAVING CONTEXT IN BLOCK");
            }
        }];
    }

データベースに他の変更はなく、コンテキストを保存するだけです。このコードの何が問題になっていますか?それはどのように見えるべきですか?

注:[StoreDataRetriever sharedRetriever] .managedObjectContextは、initWithConcurrencyType:NSPrivateQueueConcurrencyTypeを使用してappDelegateで作成されます。

4

1 に答える 1

2

そのコードで何が起こっているのですか?コンテキストをスレッドに同期的に保存してから、コンテキストプライベートキューに保存をスケジュールします。5回。したがって、基本的には、同期と非同期の2つの保存操作が互いに衝突する可能性があります。

これは明らかに問題です。プライベートキューがそのキューの外にあるコンテキストを保存することは想定されていません。コンテキストキューにスケジュールされたブロックがない場合は、現在のコンテキスト実装で機能します。しかし、それでもこれは間違っています。

…
for (int i = 0; i < 5; i++) {            
    NSLog(@"Main thread: %@, is main? %d", [NSThread currentThread], [NSThread isMainThread]);
    __block NSError *error = nil;
    __block BOOL saveOK = YES;
[context performBlockAndWait: ^{
    saveOK = [context save: &error];
}];

    if (!saveOK) {
        NSLog(@"ERROR!!!");
    }
    …

そのコードを使用すると、保存操作を同期的に実行し、最も確実に同じスレッドで実行します(GCDのおかげで)コンテキストスイッチと同期機能を節約し、そのコンテキストで2つの操作を同時に実行するリスクはありません。

NSMainQueueConcurrencyTypeを使用する場合も、例外を除いて同じルールが適用されます。そのキューは、メインスレッドとメインスレッドにのみバインドされます。NSPrivateQueueConcurrencyTypeのようなperformBlockおよびperformBlockAndWaitを使用して、任意のスレッドのメインキューを使用してコンテキストでブロックをスケジュールできます。また、(例外:)メインスレッドで直接コンテキストを使用できます。

NSConfinementConcurrencyTypeは、コンテキストを特定のスレッドにバインドします。GCDまたはブロックを使用してそのようなコンテキストを処理することはできず、バインドされたスレッドのみを処理できます。今日の時点で、その並行性モデルを使用する理由はほとんどありません。必要な場合はそれを使用しますが、絶対に必要でない場合は使用しないでください。


編集

マルチコンテキストの設定に関する非常に優れた記事は次のとおりです。http://www.cocoanetics.com/2012/07/multi-context-coredata/

于 2012-07-20T22:03:50.880 に答える