Objective c 根据子对象中可能的属性快速筛选父NSManagedObject

Objective c 根据子对象中可能的属性快速筛选父NSManagedObject,objective-c,core-data,grand-central-dispatch,nsmanagedobject,nsset,Objective C,Core Data,Grand Central Dispatch,Nsmanagedobject,Nsset,我正在做一个项目,需要一些相当复杂的过滤。我有一个RaceNSManagedObject,它附加了许多Car对象。汽车可以有多个位置对象。对于给定的比赛,我需要获得所有汽车的列表,但它们需要根据比赛进行与否进行不同的订购。如果比赛尚未开始,则需要按Car.number(简单)订购。如果比赛正在进行,他们需要按照当前位置进行排序。困难在于检索到的位置不能是集合中的最新位置,而是特定范围内的最新位置,并且可能根本没有位置(即,如果赛车退出比赛) 排序已经完成,我有一些代码工作,允许我在我的Car上设

我正在做一个项目,需要一些相当复杂的过滤。我有一个
Race
NSManagedObject,它附加了许多
Car
对象。
汽车
可以有多个
位置
对象。对于给定的比赛,我需要获得所有汽车的列表,但它们需要根据比赛进行与否进行不同的订购。如果比赛尚未开始,则需要按
Car.number
(简单)订购。如果比赛正在进行,他们需要按照当前位置进行排序。困难在于检索到的位置不能是集合中的最新位置,而是特定范围内的最新位置,并且可能根本没有位置(即,如果赛车退出比赛)

排序已经完成,我有一些代码工作,允许我在我的
Car
上设置一个
currentPosition
属性,该属性基于检索汽车的全套位置,然后使用
filteredSetUsingPredicate:
valueForKeyPath:
检索最长时间。问题是它非常慢,而且需要非常快(因为它每秒钟都会发生)。我将它包装在
dispatch\u async
中,但这导致了偶尔的冻结,因为NSManagedObjects不是线程安全的

理想情况下,我需要的是一种获得
Car
对象数组的方法,这些对象具有
Car.currentPosition
可选设置为最新的
位置(如果适用)(这是通过在最近10秒内获取最后的
位置.time
来确定的,如果存在的话)。然后,我可以自己根据
Car.currentPosition.position
属性对返回的数组进行排序,并执行其他需要执行的操作(即,将没有currentPosition的数组移动到非finisher的单独列表中)

下面是我到目前为止的(慢)代码。我要么需要一种加速的方法(某种使用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;
    }
-(void)performFetchWithCallback:(void(^)(void))完成块
{
n错误*错误;
[self.fetchedResultsController性能蚀刻:&错误];
如果(错误){
NSLog(@“错误:%@”,错误);
}
NSMutableArray*cars=[NSMutableArray];
BOOL isRacing=否;
for(Car*Car in_fetchedResultsController.fetchedObject){
位置*位置=零;
NSSet*carPositions=[[carvalueforkey:@“positions”]复制];
如果(carPositions&¤tTime>0){
NSSet*positions=[carPositions filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@“时间<%@&&time>%@”,“@(当前时间),@(当前时间-10)];
如果(positions.count>0){
NSNumber*time=[positions valueForKeyPath:@“@max.time”];
用于(位置*p处于位置){
如果([p.time isEqual:time]){
位置=p;
isRacing=是;
}
}
}
}
car.currentPosition=位置;
[汽车添加对象:汽车];
}
self.allCars=cars;
if(完成块){
completionBlock();
}
}
-(NSFetchedResultsController*)fetchedResultsController
{
如果(_fetchedResultsController!=nil){
返回_fetchedResultsController;
}
NSFetchRequest*fetchRequest=[[NSFetchRequest alloc]init];
NSEntityDescription*entity=[NSEntityDescription entityForName:@“Car”在managedObjectContext:self.managedObjectContext];
[FetchRequestSetEntity:entity];
NSSortDescriptor*排序=[[NSSortDescriptor alloc]initWithKey:@“number”升序:是];
NSPredicate*谓词=[NSPredicate谓词格式:@“raceIdentifier=%@”,_race.identifier];
[FetchRequestSetPredicate:谓词];
[FetchRequestSetSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:40];
NSFetchedResultsController*OfficedResultsController=[[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:_ManagedObjectContextSectionNameKeyPath:nil cacheName:@“Racing”];
self.fetchedResultsController=offettedResultsController;
返回_fetchedResultsController;
}
有一个名为
currentTime
的ivar,其中包含比赛开始后的秒数-用于确定应该显示哪些位置(因为位置可以提前很长时间保存)

型号:

汽车

  • raceIdentifier(NSNumber-用于限制赛车参加比赛)
  • 编号(NSNumber-赛车的起始编号-用于在比赛尚未开始时对赛车进行排序)
  • 位置(位置对象集)
位置

  • 时间(NSNumber-此位置更新的时间,以秒为单位)
  • 位置(NSNumber-赛车在比赛中的位置,即第一)

对于可能过于简单化表示歉意,但简而言之,这是应该(可能?)起作用的


在处理其他线程中的上下文时,我通常会处理大量的上下文;说我被宠坏了

你真是进退两难!当您尝试将回迁/计算放在后台线程中时,是否尝试在后台线程中保存已排序的车辆ID,通过回调将该ID集传递给主线程,然后基于这些ID在主线程中重新回迁
NSManagedObjects
?在线程获取问题中,传递
NSIntegers
已保存
- (void)performFetchWithCallback:(void (^)(void))completionBlock
{
    // Use a dictionary instead; you'll want to set instance variables on your cars in the main
    // thread
    __block NSMutableDictionary *carDict = [NSMutableDictionary dictionary];
    dispatch_queue_t main = dispatch_get_main_queue();
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,NULL), ^{
        // Perform a non-resultsController fetch with a background context, using the 
        // car, number, race identifier NSFetchRequest below

        // Then your for (car in fetchedResults) computation loop, but use a
        // mutable dictionary (carDict) instead of an array, and store car IDs as
        // your keys, and their current position as their values

        dispatch_async(main, ^{
            // Here, fetch your cars into your fetched results controller based on a
            // predicate of the carDict keys you stored (id IN %@), then do a quick
            // for (car in fetchedResults) loop and assign those currentPosition values here
            if (completionBlock) completionBlock();
        });
    });
}