web-dev-qa-db-ja.com

コアデータとスレッド/ Grand Central Dispatch

私はGrand Central Dispatch(GCD)とCore Dataの初心者です。40.000レコードをCore Dataに追加している間、UIがロックされないように、CGDでCore Dataを使用するためにあなたの助けが必要です。

CDはスレッドセーフではないことを知っているので、いくつかの記事から理解できる限り、別のコンテキストを使用し、データを保存してコンテキストをマージする必要があります。

私がまだできなかったことは、ピースをまとめることです。

だから、私のコードでは、その方法についてあなたの助けが必要です。

私が持っています:

/*some other code*/

for (NSDictionary *memberData in arrayWithResult) {

    //get the Activities for this member
    NSArray *arrayWithMemberActivities = [activitiesDict objectForKey:[memberData objectForKey:@"MemberID"]];

    //create the Member, with the NSSet of Activities
    [Members createMemberWithDataFromServer:memberData
                         andActivitiesArray:arrayWithMemberActivities
                              andStaffArray:nil
                           andContactsArray:nil
                     inManagedObjectContext:self.managedObjectContext];
}

これをバックグラウンドで動作するように変換し、保存が完了したら、40.000オブジェクトの保存中にUIをブロックせずにデータを保存してUIを更新するにはどうすればよいですか?

41
Rui Lopes

ここにあなたが試す良い例があります。ご不明な点がございましたら、お気軽にご連絡ください。

self.mainThreadContext... // This is a reference to your main thread context
NSPersistentStoreCoordinator *mainThreadContextStoreCoordinator = [self.mainThreadContext persistentStoreCoordinator];
dispatch_queue_t request_queue = dispatch_queue_create("com.yourapp.DescriptionOfMethod", NULL);
dispatch_async(request_queue, ^{

    // Create a new managed object context
    // Set its persistent store coordinator
    NSManagedObjectContext *newMoc = [[NSManagedObjectContext alloc] init];
    [newMoc setPersistentStoreCoordinator:mainThreadContextStoreCoordinator]];

    // Register for context save changes notification
    NSNotificationCenter *notify = [NSNotificationCenter defaultCenter];
    [notify addObserver:self 
               selector:@selector(mergeChanges:) 
                   name:NSManagedObjectContextDidSaveNotification 
                 object:newMoc];

    // Do the work
    // Your method here
    // Call save on context (this will send a save notification and call the method below)
    BOOL success = [newMoc save:&error];
    if (!success)
        // Deal with error
    [newMoc release];
});
dispatch_release(request_queue);

そして、コンテキスト保存通知に応じて:

- (void)mergeChanges:(NSNotification*)notification 
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.mainThreadContext mergeChangesFromContextDidSaveNotification:notification waitUntilDone:YES];
    });
}

また、バックグラウンドスレッドコンテキストを使い終わったら、通知センターからオブザーバーを削除することを忘れないでください。

[[NSNotificationCenter defaultCenter] removeObserver:self];
56
Rog

これは、GCDとUIを最も簡単に説明したスニペットです。 doWorkを、CoreDataを機能させるコードに置き換えることができます。

CDとスレッドの安全性に関して、GCDの優れた点の1つは、アプリケーション(サブシステム)の領域からセクションを分割して、それらを同期し、同じキューで確実に実行されるようにすることです。すべてのCoreData作業をcom.yourcompany.appname.dataaccessという名前のキューで実行できます。

サンプルには、長時間実行中の作業を起動するボタンとステータスラベルがあり、bg作業の実行中にスライダーを移動できることを示すためにスライダーを追加しました。

// on click of button
- (IBAction)doWork:(id)sender
{
    [[self feedbackLabel] setText:@"Working ..."];
    [[self doWorkButton] setEnabled:NO];

    // async queue for bg work
    // main queue for updating ui on main thread
    dispatch_queue_t queue = dispatch_queue_create("com.sample", 0);
    dispatch_queue_t main = dispatch_get_main_queue();

    //  do the long running work in bg async queue
    // within that, call to update UI on main thread.
    dispatch_async(queue, 
                   ^{ 
                       [self performLongRunningWork]; 
                       dispatch_async(main, ^{ [self workDone]; });
                   });

    // release queues created.
    dispatch_release(queue);    
}

- (void)performLongRunningWork
{
    // simulate 5 seconds of work
    // I added a slider to the form - I can slide it back and forth during the 5 sec.
    sleep(5);
}

- (void)workDone
{
    [[self feedbackLabel] setText:@"Done ..."];
    [[self doWorkButton] setEnabled:YES];
}
8
bryanmac

このブログ投稿には、コアデータの同時実行性とサンプルコードの詳細な説明があります。 http://www.duckrowing.com/2010/03/11/using-core-data-on-multiple-threads/

3
Michael

チェックできる別の情報源を追加する

ThreadedCoreData

最近更新されたAppleのiOS開発者ライブラリのサンプルコード(2013-06-09)

コアデータプログラミングガイドに記載されている最初の推奨パターンに従って、マルチスレッド環境でコアデータを使用する方法を示します。

SeismicXMLサンプルに基づいて、世界中の最近の地震に関するデータを提供する米国地質調査所(USGS)からRSSフィードをダウンロードして解析します。このサンプルの違いは、Core Dataを使用して永続的に地震を保存することです。アプリを起動するたびに、新しい地震データがダウンロードされ、NSOperationで解析されます。NSOperationは重複をチェックし、新しく作成された地震を管理対象オブジェクトとして保存します。

Core Dataを初めて使用する場合は、SeismicXMLサンプルをこのサンプルと比較して、アプリケーションにCore Dataを導入するために必要な要素を確認しておくと役立ちます。

1
angelos.p

これを行うには、永続ストアコーディネーターを新しいコンテキストに接続するよりもはるかに簡単です。これは、スレッドセーフでもありません。

NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrency];
[context setParentContext:<main thread context here>];

[context performBlock:^{

    ...
    // Execute all code on current context
    ...

}];

NSError *error = nil;
[context save:&error];
if (!error) {
    [context.parentContext save:&error];
    if (error) {
        NSLog(@"Could not save parent context: %@", error);
    }
}
else {
    NSLog(@"Could not save context: %@", error);
}

マルチコンテキストコアデータの使用方法に関する素晴らしいチュートリアル:

http://www.cocoanetics.com/2012/07/multi-context-coredata/

0
Simon Germain

したがって、これに対する選択された答えは、ほぼ2年前のものであり、いくつかの問題があります。

  1. これはARCに対応していません-newMocのリリースコールを削除する必要があります-ARCはそれでもコンパイルできません
  2. ブロック内でweakSelf/strongSelfダンスを実行する必要があります-そうでない場合は、おそらくオブザーバーの作成で保持ループを作成しています。 Appleのドキュメントはこちら: http://developer.Apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html
  3. @RyanGがコメントしたのは、なぜ彼がブロックしているのかです。私の推測では、最近編集されたメソッドにはwaitUntilDone:YESが含まれているためです。ただし、メインスレッドがブロックされます。おそらくwaitUntilDone:NOが必要ですが、これらの変更イベントから発生するUI更新があるかどうかもわかりません。そのため、テストが必要になります。

-編集-

#3をさらに詳しく見る-waitUntilDone:YESはマネージコンテキストオブジェクトの有効なmethodSignatureではないので、それはどのように機能しますか?

0
Matt S.