我正在做一个需要一些相当复杂的过滤的项目。我有一个Race
NSManagedObjectCar
附加了许多对象。Car
可以有多个Position
对象。对于给定的比赛,我需要获取所有汽车的列表,但需要根据比赛是否进行而对它们进行不同的排序。如果比赛还没有开始,他们需要由Car.number
(简单)订购。如果比赛正在进行,则需要按当前位置排序。困难在于检索到的位置不能是集合中最新的,而是特定范围内的最新的,并且可能根本没有位置(即如果赛车出局)。
排序全部完成,我有一些代码工作,允许我根据检索汽车的完整位置集,然后使用和检索最大时间来设置我的currentPosition
属性。这样做的问题是它非常慢,而且需要非常快(因为它每秒都会发生)。我将它包裹在其中,但由于 NSManagedObjects 不是线程安全的,因此导致偶尔冻结。Car
filteredSetUsingPredicate:
valueForKeyPath:
dispatch_async
理想情况下,我需要一种方法来获取对象的 NSArray,如果适用,这些Car
对象可以Car.currentPosition
选择设置为最新的(如果存在,则通过在最后 10 秒内获取最后一个来确定)。然后,我可以自己根据属性对返回的数组进行排序,并执行我需要做的其他部分(即将那些没有 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 - 用于将 Car 限制为 Race)
- number (NSNumber - 赛车的起始编号 - 用于在比赛尚未开始时对赛车进行排序)
- 位置(位置对象的 NSSet)
位置
- time (NSNumber - 此位置更新的时间,以秒为单位)
- 位置(NSNumber - 赛车在比赛中的位置,即第一名)