いくつかのコア データ エントリを選択して並べ替えています。これは簡単ですが、距離による並べ替えの計算のため、別のスレッドに入れたいと思いました。#ifdef THREADS
以下のセクション内にコードを追加して、他のスレッド用に新しい NSManagedObjectController を作成するという通常の方法でそれを行いました。
これで、ユーザー インターフェイスを遅くすることなく、フェッチ、並べ替え、整理を行うことができ、準備ができたらテーブルが更新されます。
しかし、私はローカル管理対象オブジェクト コンテキストでフェッチを行っているため、フェッチしたオブジェクトはメイン スレッドでは有効ではありません。実際、それらはテーブル ビュー セルから消えてしまいます。
ですから、私の質問は次のとおりです。1) メインのマネージド オブジェクト コンテキストを使用しても問題ないでしょうか。ローカル コンテキストをまったく作成せず、読み取りのみを行っているからです。2) 並べ替えと整理の後、検索管理オブジェクト コンテキスト オブジェクトの ObjectID 値を使用して、メイン スレッドのメイン管理オブジェクト コンテキストからすべてのオブジェクトを調べて再取得する必要がありますか? 3) メインのマネージド オブジェクト コンテキストでフェッチを行う必要がありPerformBlockAndWait
ますが、スレッド上で返されたオブジェクトの並べ替えと整理を維持する必要がありsearchQ
ますか? 4) 他に考えたことがないことはありますか?
- (void) fetchShopLocations {
#ifdef THREADS
dispatch_queue_t searchQ = dispatch_queue_create( "searchQueue", NULL );
dispatch_async( searchQ, ^{
#endif
NSError *error;
#ifdef THREADS
// Make a managed object context that can be not on the main thread
NSManagedObjectContext *localContext = [[NSManagedObjectContext alloc] init];
[localContext setPersistentStoreCoordinator: [self.managedObjectContext persistentStoreCoordinator]];
#else
NSManagedObjectContext *localContext = self.managedObjectContext;
#endif
// Get the array of locations sorted by distance
NSArray *locations = NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName: NSStringFromClass([Shop class])];
// No sort descriptors since I cannot sort on things not in the database
NSArray *locations = [context executeFetchRequest: request error: &error];
if( !locations ) {
NSLog( @"Shop fetch error: %@", error );
return;
}
locations = [locations sortedArrayUsingComparator: ^NSComparisonResult( Shop *loc1, Shop *loc2 ) {
double dist1 = [loc1 distanceFromLatitude: self.referenceLatitude andLongitude: self.referenceLongitude];
double dist2 = [loc2 distanceFromLatitude: self.referenceLatitude andLongitude: self.referenceLongitude];
if( dist1 < dist2 )
return NSOrderedAscending;
else if( dist1 > dist2 )
return NSOrderedDescending;
return [[loc1 name] localizedCaseInsensitiveCompare: [loc2 name]];
}];
NSMutableArray *sections = [NSMutableArray arrayWithCapacity: 5];
NSMutableDictionary *section;
NSMutableArray *rows;
section = [NSMutableDictionary dictionaryWithCapacity: 2];
rows = [NSMutableArray arrayWithCapacity: locations.count];
__block double sectionLimitUserUnits = 5.0;
__block double sectionLimitKilometers;
if( self.userUnits == LocationDistanceUnitsMiles )
sectionLimitKilometers = sectionLimitUserUnits * KILOMETERS_PER_MILE;
else sectionLimitKilometers = sectionLimitUserUnits;
[section setValue: [NSString stringWithFormat: @"Within %g", sectionLimitUserUnits] forKey: kSectionHeaderTitleKey];
[locations enumerateObjectsUsingBlock: ^( Shop *loc, NSUInteger idx, BOOL *stop ) {
double distance = [loc distanceFromLatitude: self.referenceLatitude andLongitude: self.referenceLongitude];
if( distance > self.maxDistance ) {
*stop = YES;
} else {
while( distance > sectionLimitKilometers ) {
[section setValue: [rows copy] forKey: kRowKey];
[sections addObject: [section copy]];
[section removeAllObjects];
[rows removeAllObjects];
sectionLimitUserUnits += 5.0;
if( self.userUnits == LocationDistanceUnitsMiles )
sectionLimitKilometers = sectionLimitUserUnits * KILOMETERS_PER_MILE;
else sectionLimitKilometers = sectionLimitUserUnits;
[section setValue: [NSString stringWithFormat: @"Within %g", sectionLimitUserUnits] forKey: kSectionHeaderTitleKey];
}
[rows addObject: loc];
}
}];
[section setValue: [rows copy] forKey: kRowKey];
[sections addObject: [section copy]];
#ifdef THREADS
dispatch_async( dispatch_get_main_queue(), ^{
#endif
self.sections = sections;
[self.tableView reloadData];
#ifdef THREADS
});
});
dispatch_release( searchQ );
#endif
}
スレッド競合の非決定論的な性質のため、シミュレーターで動作するように見えるものをテストするだけでは当てにならないことを私は知っています。
前もって感謝します!