2017-08-30 12 views
0

Core Dataアプリで複数のコンテキストを使用していて、最近になってコアデータの並行性がクラッシュしました。これらを追跡するのに役立つ-com.apple.CoreData.ConcurrencyDebug 1を追加しましたが、表示されている問題を解決する方法がわかりません。コアデータの並行性の問題と修正方法

- (void)getEvents:(void (^)(NSArray *fetchedItems))completionBlock { 

    // Initialize Fetch Request 
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"ZSSCDEvent"]; 

    // Initialize Asynchronous Fetch Request 
    NSAsynchronousFetchRequest *asynchronousFetchRequest = [[NSAsynchronousFetchRequest alloc] initWithFetchRequest:request completionBlock:^(NSAsynchronousFetchResult *result) { 

     dispatch_async(dispatch_get_main_queue(), ^{ 

      // Dismiss Progress HUD 
      [SVProgressHUD dismiss]; 

      // Process Asynchronous Fetch Result 
      if (result.finalResult) { 

       NSArray *results = result.finalResult; 

       completionBlock(results); 

       // Reload Table View 
       [self.activityIndicator stopAnimating]; 
       [self.tableViewList reloadData]; 

      } 

     }); 
    }]; 

    // Execute Asynchronous Fetch Request 
    [self.managedObjectContext performBlock:^{ 

     // Execute Asynchronous Fetch Request 
     NSError *asynchronousFetchRequestError = nil; 
     NSAsynchronousFetchResult *asynchronousFetchResult = (NSAsynchronousFetchResult *)[self.managedObjectContext executeRequest:asynchronousFetchRequest error:&asynchronousFetchRequestError]; 

     if (asynchronousFetchRequestError) { 
      NSLog(@"Unable to execute asynchronous fetch result."); 
      NSLog(@"%@, %@", asynchronousFetchRequestError, asynchronousFetchRequestError.localizedDescription); 
     } 

    }]; 

} 

これは私にEnqueued from com.apple.main-thread (Thread 1)エラーを与える:ここで

は私がやっているものです。これは私が混乱しているところです。なぜなら、私はこれをメインスレッドで実行しており、私のプライベートコンテキストをここで使う必要はないと思っています。

enter image description here

なぜ私はここに同時実行の問題を取得しています上の任意のアイデア?

EDIT:それは他の誰かが、正確な問題を持っていたように見え、それはXcodeのバグであると考えて:CoreData asynchronous fetch causes concurrency debugger error

答えて

0

すべてmanagedObjectは、コンテキストを持っています。各コンテキストには、実行可能なスレッドが1つしかありません。 ManagedObjectsはスレッドセーフではありません。完了したブロックでmanagedObjectsを渡すのは悪い習慣です。どのマネージオブジェクトがどのスレッド上にあるはずなのか把握するのは難しいかもしれません。また、あなたが正しいスレッド上でそれを渡しているとしても、それはまだ悪い習慣です。 dispatch_asyncを実行すると、そのエンティティが一時的にデータベースから削除され、managedObjectにアクセスするとクラッシュする可能性があります。フェッチを行うメソッドは、どのコンテキストを使用して同期的に返すかを明示的に指示することをお勧めします。あなたのコードでは、このメソッドはself.managedObjectContextを使用していますが、関連するスレッドをコードで調べる方法はありません。さらに、コンテキストへのポインタが変更され、追跡が非常に困難なバグが発生する可能性があります。

NSAsynchronousFetchResultにはmanagedObjectsが含まれているため、スレッドセーフではなく、その完了ブロック(オブジェクトの正しいスレッドで実行されている)内でのみ使用できます。それらを別のスレッドに渡すことはできません。それらをブロックで返すと、そのコードは別のスレッドにそれらを渡さなければなりません。ブロック内でそれらとやり取りする必要があるものはすべて実行し、それらを破棄する必要があります。

ユーザーに情報を表示する必要がある場合は、一般に、メインスレッドでフェッチを同期して実行し、メインスレッドコンテキストに関連付けられたmanagedObjectを取得する方がよいでしょう。フェッチが長引くと、それを修正する必要があります。フェッチが長くかかる理由はありません。あなたのケースでは、データベース内のすべての項目を取得しているようです。それは間違いです。あなたは必要なものだけを得るために述語を使うべきです。

もう1つの方法は、managedObjectsの値をスレッドセーフオブジェクト(辞書またはNSObjectサブクラス)にコピーすることです。

TL; DRおそらくNSAsynchronousFetchRequestは必要ありません。メインスレッドで定期的なフェッチ要求を使用し、同期的に戻ります。述語を使用して、結果を実際に表示しているオブジェクトのみに限定します。

関連する問題