iOS 5では、NSPrivateQueueConcurrencyType
を使用してMOCを初期化し、performBlock:
でフェッチを実行することにより、バックグラウンドスレッドでデータをすばやくフェッチする新しい方法が導入されました
Core Dataの経験則の1つは、管理対象オブジェクトをスレッド/キュー間で共有できないことです。それでもperformBlock:
はそうですか?以下は:
[context performBlock:^{
// fetch request code
NSArray *results = [context executeFetchRequest:request error:nil];
dispatch_async(dispatch_get_main_queue(), ^(void) {
Class *firstObject = [results objectAtIndex:0];
// do something with firstObject
});
}];
結果の配列/オブジェクトをbgキューとメインキューの間で共有しているため、まだ受け入れられませんか?それを行うために、引き続き管理オブジェクトIDを使用する必要がありますか?
NSPrivateQueueConcurrencyType
を使用する場合、そのコンテキストに触れるanythingを実行する必要がありますorそのコンテキストに属するオブジェクト-performBlock:
メソッド内。
これらのオブジェクトをメインキューに戻すため、上記のコードは不正です。ただし、新しいAPIはこれを解決するのに役立ちます。メインキューに関連付けられた1つのコンテキストを作成します。つまり、NSMainQueueConcurrencyType
を使用します。
// Assume we have these two context (They need to be set up. Assume they are.)
NSManagedObjectContext *mainMOC = [[[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType] autorelease];
NSManagedObjectContext *backgroundMOC = [[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType] autorelease];
// Now this can safely be called from ANY thread:
[backgroundMOC performBlock:^{
NSArray *results = [backgroundMOC executeFetchRequest:request error:nil];
for (NSManagedObject *mo in results) {
NSManagedObjectID *moid = [mo objectID];
[mainMOC performBlock:^{
NSManagedObject *mainMO = [mainMOC objectWithID:moid];
// Do stuff with 'mainMO'. Be careful NOT to use 'mo'.
}];
}
}];
内部の[mainMOC performBlock:]
呼び出しを独自のメソッドに移動すると、混乱が少なくなります。また、オブジェクトIDごとにブロックを実行する代わりに、オブジェクトIDの配列をメインスレッドのコンテキストに渡すこともできます。それはあなたのニーズに依存します。
ダニエル・エガートが説明するように、これは間違いなくまだ事実です。例外はNSMainQueueConcurrencyType
で、メインスレッドで(およびperformBlockメカニズムを介して他のスレッドから)管理オブジェクトコンテキストとオブジェクトを安全に使用することもできます。これの有用性は控えめに言っても過言ではありません!
iOS 5では、親コンテキストの概念も導入されました。これにより、バックグラウンド操作が大幅に簡素化され、通知を使用してスレッド間の変更を伝播することを心配する必要がなくなります。
WWDC 2012ビデオ「セッション214-コアデータのベストプラクティス」 は、両方の主題についてより詳細に説明されており、非常に包括的です。このビデオは、Core Dataを使用するすべての人にとって不可欠なものです。