4

バックグラウンドでいくつかのJSONオブジェクトをダウンロードしようとしていますが、かなりのマルチスレッドを実行しています。操作が完了すると、このアサーションが失敗することに気付きました。

NSAssert([user.managedObjectContext isEqual:[AppUser managedObjectContext]],@"Different contexts");

[AppUser managedObjectContext]で定義されたメインコンテキストに変更をマージするにはどうすればよいですか?

4

3 に答える 3

11

MarcusZarraによるコアデータのインポートと表示に関する次のリンクを読むことをお勧めします。

スレッドを扱う場合、作成する各スレッドは、 jrturtonが提供したリンクに記述されている独自のコンテキストを持っている必要があります。次に、メインコンテキスト(メインスレッドで作成したもの)と他のコンテキスト(コンテキストで使用するもの)の間で変更をマージする場合は、メインスレッドでリッスンする必要がありNSManagedObjectContextDidSaveNotificationます

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextHasChanged:) name:NSManagedObjectContextDidSaveNotification object:nil];

のようにマージします

- (void)contextHasChanged:(NSNotification*)notification
{
  if ([notification object] == [self mainObjectContext]) return;

  if (![NSThread isMainThread]) {
    [self performSelectorOnMainThread:@selector(contextHasChanged:) withObject:notification waitUntilDone:YES];
    return;
  }

  [[self mainObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}

通知オブジェクトには、スレッドコンテキストで行った変更が含まれています。

いくつかのメモ

スレッド化は困難です。私が提供したリンクは、NSOperationそのコンテキストでを使用しています。これはセットアップが非常に簡単ですが、iOS 5以降、あなたの生活を楽にするいくつかの機能があります。

たとえば、別のスレッドでコンテキストを作成するには、次のように実行できます。

// create a context with a private queue so access happens on a separate thread.
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
// insert this context into the current context hierarchy
context.parentContext = context;
// execute the block on the queue of the context
[context performBlock:^{

      // do your stuff (e.g. a long import operation)

      // save the context here
      // with parent/child contexts, saving a context pushes the changes out of the current context
      NSError* error = nil;
      [context save:&error];
}];

さらに、のドキュメントを見ることができますUIManagedDocument。このクラスはCoreDataとうまく統合され、CoreDataスタックの使用を回避できます。

それが役に立てば幸い。

于 2012-05-01T22:10:43.483 に答える
1

特定の状況(バックグラウンドでJSONをダウンロードする)は非常に一般的です。私は、複数のコンテキストなしで実行できる多くの実装を見てきました。

多くの場合、最も簡単で最も堅牢な方法は、ダウンロードを実行するオブジェクトに、プロトコルまたはダウンロードの終了の通知を介してメインスレッドに通知させることです。次に、メインスレッドで保存を行います。

于 2012-05-01T22:19:45.750 に答える
0

私の状況では、RKObjectLoaderのサブクラスを使用していますが、スレッドと操作が多すぎて、何が起こっているかを追跡できません。ロードされたオブジェクトにそれ自体を保存するように依頼することで、RKObjectStoreに変更をマージするようにうまく依頼できることがわかりました。[AppUser managedObjectContext](私が自分自身を救うように頼む前に、それは間違っていました)

正しい解決策は、ロードされたオブジェクトに、次のようにそれ自体を独自のコンテキストで保存するように要求することでした。

- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {

    AppUser* user = nil;
    for (id object in objects)
    {
         user = object;
    }
    NSError* error = nil;


/**this call fires the:    
//    - (void)mergeChanges:(NSNotification *)notification
within the rkmanagedobjectstore class and merges changes made in this background operation over to the main contxt
 */
 [[user managedObjectContext] save:nil];

}
于 2012-05-02T18:08:23.480 に答える