2012-09-24 10 views
10

MagicalRecord 2.0.3を使用していて、データをバックグラウンドで保存する方法を実際には分かりません。複数のオブジェクトをバックグラウンドで作成する方法は?

文書によると、このような何かが動作するはずです:

[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { 
    // Do this hundreds of times 
    [MyObject createInContext:localContext]; 
}]; 

はしかし、何もデータベースに保存されません。私は複数の人がこれに似たソリューションを掲示見てきました:

[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { 
    // Do this hundreds of times 
    [MyObject createInContext:localContext]; 
} completion:^{ 
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
     [[NSManagedObjectContext defaultContext] saveNestedContexts]; 
    }]; 
}]; 

これは私のデータセットで(保存がメインスレッド上で発生するのでしかし、私のアプリケーションは、しばらくの間応答しない、データベース内の自分のデータを保存し、約3秒は長すぎます)。

は私もこれを試してみたが、それはまた、ブロックは、最大節約しながら:

self.queue = [[NSOperationQueue alloc] init]; 

[self.queue addOperationWithBlock:^{ 
    NSManagedObjectContext *localContext = [NSManagedObjectContext contextForCurrentThread]; 

    // Do this hundreds of times 
    [MyObject createInContext:localContext]; 

    [localContext saveNestedContexts]; 
}]; 

そして最後に、このコードで同じブロッキング効果:

dispatch_queue_t syncQueue = dispatch_queue_create("Sync queue", NULL); 
dispatch_async(syncQueue, ^{ 
    NSManagedObjectContext *localContext = [NSManagedObjectContext contextForCurrentThread]; 

    // Do this hundreds of times 
    [MyObject createInContext:localContext]; 

    [[NSManagedObjectContext contextForCurrentThread] saveNestedContexts]; 
}); 

ので、最善の方法は何ですかこれを解決するには?私はバックグラウンドで何百ものオブジェクトを作成する必要があり、アプリケーションは応答し続ける必要があります。

+0

の仕事ができる方法の例を見つけることができる新しいネストされたコンテキストがMagicalRecordで保存するAPIの多くに大混乱をもたらすために始めています。私はこれらの問題を認識していますが、いくつかの修正が今では議論されていますが、私は常に提案することができます。 – casademora

+2

おそらく、MRのようなフレームワークなしでCore Dataを使うのが一番良いでしょうか? – Hunter

+0

MagicalRecordを使用して解決策を見つけましたか?私は同じ問題(バックグラウンドで更新中のUIロック)を持っており、解決策を見つけることができません。ありがとう! – RyanG

答えて

6

MagicalRecordは、バックグラウンドで作業するときに子コンテキストを使用します。小さな変更でうまく動作しますが、大量のデータをインポートするときに過剰なメインスレッドのブロックが発生します。

これを行う方法は、並列NSManagedObjectContextを使用して、NSManagedObjectContextDidSaveNotification通知とmergeChangesFromContextDidSaveNotificationメソッドで自分自身をマージすることです。以下のパフォーマンステストを参照してください。http://floriankugler.com/blog/2013/5/11/backstage-with-nested-managed-object-contexts

ネストされたコンテキストを保存するときは、すべてを親コンテキストにコピーする必要があります。これに対して、フェッチされていないオブジェクト(マージ対象のコンテキスト内)は、mergeChangesFromContextDidSaveNotificationによってマージされません。これはそれをより速くするものです。

バッチを保存してNSFetchResultsControllerを使用した直後にこれらの結果を表示したい場合は、問題が発生することがあります。この質問を見て、よりパフォーマンスのヒントについては NSFetchedResultsController with predicate ignores changes merged from different NSManagedObjectContext

Implementing Fast and Efficient Core Data Import on iOS 5

は、独自のコンテキストを作成して解決のため、次の質問を参照してください。

NSManagedObjectContext *importContext = [[NSManagedObjectContext alloc] 
          initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
[importContext setPersistentStoreCoordinator:yourPersistentStoreCoordinator]; 
[importContext setUndoManager:nil]; // For importing you don't need undo: Faster 

// do your importing with the new importContext 
// … 

NSError* error = nil; 
if(importContext.hasChanges) { 
    if(![importContext save:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    } 
} 

管理オブジェクトコンテキストへの保存をリッスンしていることを確認してください。

[[NSNotificationCenter defaultCenter] 
       addObserver:singleton 
       selector:@selector(contextDidSave:) 
        name:NSManagedObjectContextDidSaveNotification object:nil]; 

あなたは自分で変更をマージします。あなたがあなたのCoredataオブジェクトと背景の作業のいずれかの種類を行う必要があるので、もし

- (void) contextDidSave:(NSNotification*) notification 
{ 
    if(![notification.object isEqual:self.mainContext]) { 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self.mainContext mergeChangesFromContextDidSaveNotification:notification]; 
    }); 
    } 
} 
+0

これはどのように正確に機能しますか?大量のデータをインポートするために私のメインスレッドがブロックされているという問題に直面しています。私はMagicalRecordを使っていますが、ここで書いていることを達成することはできません。 – swalkner

+0

@swalkner詳細を提供する答えを編集しました。 – Onato

1

管理オブジェクトコンテキストはスレッドセーフではありません(つまり、メインUIをブロックすることなく、長時間実行されるインポート/エクスポート機能)あなたがしたいでしょうそれはバックグラウンドスレッド上のものです。

これらの場合、バックグラウンドスレッドで新しい管理対象オブジェクトコンテキストを作成し、コアデータ操作を繰り返して、変更内容をメインコンテキストに通知する必要があります。

あなたが、これはここに

Core Data and threads/Grand Central Dispatch

関連する問題