かなり複雑なフィルタリングが必要なプロジェクトに取り組んでいます。Race
多数のCar
オブジェクトが接続されたNSManagedObject があります。Car
には複数のPosition
オブジェクトを含めることができます。特定のレースについて、すべての車のリストを取得する必要がありますが、レースが開催されているかどうかに基づいて異なる順序で並べる必要があります。Car.number
レースが開始されていない場合は、 (単純)で注文する必要があります。レースが行われている場合は、現在の位置で並べ替える必要があります。難しいのは、検索された位置がセット内の最新の位置ではなく、特定の範囲内の最新の位置であり、位置がまったく存在しない可能性があることです (つまり、車がレースから外れている場合)。
並べ替えがすべて完了し、車の位置の完全なセットを取得し、およびを使用して最大時間を取得することに基づいて、currentPosition
プロパティを設定できるコードが動作しています。これに関する問題は、非常に遅く、非常に高速である必要があることです (1 秒ごとに発生するため)。私はそれをラップしましたが、NSManagedObjects がスレッドセーフではないため、時折フリーズが発生しました。Car
filteredSetUsingPredicate:
valueForKeyPath:
dispatch_async
私が理想的に必要としているのは、必要に応じて最新に設定されたCar
オブジェクトの NSArray を取得する方法です (存在する場合は、過去 10 秒以内に最後を取得することによって決定されます)。次に、返された配列をプロパティに基づいて自分で並べ替え、必要な他のビットを実行できます (つまり、 currentPosition のないものを非フィニッシャーの別のリストに移動します)。Car.currentPosition
Position
Position.time
Car.currentPosition.position
以下は、これまでの(遅い)コードです。これを高速化する方法 (スレッドの問題を引き起こさずに dispatch_async を使用する何らかの方法) か、CoreData からの初期フェッチを行うためのより良い方法が必要です。
現在のコード:
- (void)performFetchWithCallback:(void (^)(void))completionBlock
{
NSError *error;
[self.fetchedResultsController performFetch:&error];
if (error) {
NSLog(@"ERROR: %@", error);
}
NSMutableArray *cars = [NSMutableArray array];
BOOL isRacing = NO;
for (Car *car in _fetchedResultsController.fetchedObjects) {
Position *position = nil;
NSSet *carPositions = [[car valueForKey:@"positions"] copy];
if (carPositions && currentTime > 0) {
NSSet *positions = [carPositions filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"time < %@ && time > %@", @(currentTime), @(currentTime-10)]];
if (positions.count > 0) {
NSNumber *time = [positions valueForKeyPath:@"@max.time"];
for (Position *p in positions) {
if ([p.time isEqual:time]) {
position = p;
isRacing = YES;
}
}
}
}
car.currentPosition = position;
[cars addObject:car];
}
self.allCars = cars;
if (completionBlock) {
completionBlock();
}
}
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Car" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"number" ascending:YES];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"raceIdentifier = %@", _race.identifier];
[fetchRequest setPredicate:predicate];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:40];
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:_managedObjectContext sectionNameKeyPath:nil cacheName:@"Racing"];
self.fetchedResultsController = theFetchedResultsController;
return _fetchedResultsController;
}
レースが開始されてからの秒数を含むivar という名前currentTime
があります。これは、どのポジションを表示するかを決定するために使用されます (ポジションはかなり前に保存できるため)。
モデル:
車
- raceIdentifier (NSNumber - 車をレースに限定するために使用)
- number (NSNumber - 車の開始番号 - レースが開始されていないときに車を並べ替えるために使用されます)
- 位置 (位置オブジェクトの NSSet)
位置
- time (NSNumber - この位置更新の秒単位の時間)
- 位置 (NSNumber - レースでの車の位置、つまり 1 位)