0

NSFetchedResultsController に接続されたテーブル ビューがあり、対応する managedObjectContext は self.myDatabase.managedObjectContext です。

self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                    managedObjectContext:self.myDatabase.managedObjectContext
                                                                      sectionNameKeyPath:nil
                                                                               cacheName:nil];

ここで、ユーザーがページを更新するたびに、次のコードを実行します。本質的に、データをロードする新しいスレッドを作成し、MOC セーフ スレッドで新しいデータを更新/保存します。

dispatch_queue_t fetchQ = dispatch_queue_create("fetcher", NULL);
dispatch_async(fetchQ, ^{        
    NSArray *data = [MyAPI myData];   

    [document.managedObjectContext performBlock:^{
        for (NSDictionary *info in data) {
            [MyEntity createOrUpdateGivenInfo:info andManagedObjectContext:self.myDatabase.managedObjectContext];
        }
    }];
});
dispatch_release(fetchQ);

これは正常に機能します。更新を取得すると、テーブル ビューにすべてが正しく表示されます。唯一の問題は、おそらくメインスレッドで保存/更新を行っているため、UI が応答しないことです。そこで、この変更を加えてバックグラウンド スレッドで実行することを検討しました。

NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] init WithConcurrencyType:NSPrivateQueueConcurrencyType];
    [backgroundContext setParentContext:self.myDatabase.managedObjectContext];

    [backgroundContext performBlock:^{      
      NSArray *data = [MyAPI myData];   

      for (NSDictionary *info in data) {
            [MyEntity createOrUpdateGivenInfo:info andManagedObjectContext:backgroundContext];
        }

      [backgroundContext save:nil];

      [document.managedObjectContext performBlock:^{
        [document updateChangeCount:UIDocumentChangeDone];
      }];
    }];

ただし、UI はレスポンシブになりましたが、テーブル ビューで多くの問題が発生します。既存のエントリを更新する代わりに、テーブルに余分なエントリ (存在しないはずの重複) が表示されます。2 つのコンテキストが同期/マージされていないことが原因である可能性があると思いますが、以前の SO の投稿を読んで、backgroundContext で save を呼び出し、メイン MOC で updateChangeCount を呼び出すだけでよいと考えるようになりました。アプリを再起動すると、もう一度更新するまで、すべてが正常に機能します。

誰でも助けてくれる人はいますか。私は文字通り私の髪を引っ張り始めています。

この謎が解けたらビールを差し上げます。

4

1 に答える 1

2

UIManagedDocumentNSPrivateQueueConcurrencyTypeのルート コンテキストと の子コンテキストの2 つのコンテキストが作成されますNSMainQueueConcurrencyType

これがメインスレッドのコンテキストであるため、あなたが行ったようにあなたをNSFetchedResultsControllerに接続します。document.managedObjectContext

読み取り/書き込みは、バックグラウンド スレッドで自動的に行われます。UIManagedDocumentそれを処理します。心配する必要はありません。

重いものを自分で処理する必要がある場合は、別の管理対象オブジェクトを作成しNSMainQueueConcurrencyTypeて、document.managedObjectContextその親にします。

私はあなたのコードを読みましたが、これはあなたがしていることであり、これはうまくいくはずです。それがまさに私のアプリでのやり方です。NSFetchedResultsControllerしかし、フレームワークのバグがあるのではないかと疑って重複したエントリを報告している他の何人かの人々を見てきました。

あなたのプロジェクトを共有したいなら、私は見てみたいと思います。

于 2012-07-06T06:44:59.083 に答える