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();
});
});
}