Ios 仅将NSSortDescriptor应用于NSFetchedResultsController的NSPreditate筛选的实体
对于TableViewController,我正在创建一个NSFetchedResultsController 模型看起来像:EntityA>EntityB。在下面的代码中,这种关系称为entityRelationship。EntityB有一个名为attribute的NSNumber属性 我需要对结果进行筛选和排序。我是这样做的:Ios 仅将NSSortDescriptor应用于NSFetchedResultsController的NSPreditate筛选的实体,ios,core-data,nspredicate,nsfetchedresultscontroller,nssortdescriptor,Ios,Core Data,Nspredicate,Nsfetchedresultscontroller,Nssortdescriptor,对于TableViewController,我正在创建一个NSFetchedResultsController 模型看起来像:EntityA>EntityB。在下面的代码中,这种关系称为entityRelationship。EntityB有一个名为attribute的NSNumber属性 我需要对结果进行筛选和排序。我是这样做的: predicate = [NSPredicate predicateWithFormat:@"entityRelationship.@count > 0"];
predicate = [NSPredicate predicateWithFormat:@"entityRelationship.@count > 0"];
[fetchRequest setPredicate:predicate];
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"entityRelationship.@avg.attribute"
ascending:NO];
基本上,我需要显示具有非空entityRelationship的所有实体,并根据entityB属性的平均值对它们进行排序
显示的代码引发异常:*由于未捕获的异常“NSRangeException”而终止应用程序,原因:“-[\uu NSCFString characterAtIndex:]:范围或索引超出范围”
sortDescriptor不是只应用于谓词筛选的结果吗?我如何在一个请求中实现这一点?(由于此请求链接到NSFetchedResultsController,因此我不想先获取然后排序)
谢谢
编辑
根据邓肯的回答,我找到了解决办法。我仍然觉得用我的问题中的相同例子发布我的答案是恰当的
在基于EntityB的类别中,我覆盖了属性的setter。(我需要知道EntityA中所有属性的平均值,以便对它们进行排序)。代码如下:
- (void)setAttribute:(NSNumber *)attribute
{
[self willChangeValueForKey:@"attribute"];
[self setPrimitiveValue:attribute forKey:@"attribute"];
[self didChangeValueForKey:@"attribute"];
EntityA *entityA = self.entityA;
float mean = 0;
int nbItems = 0;
for (EntityB *b in entityA.entityB)
{
mean += [b.attribute floatValue];
nbItems++;
}
[entityA setAvgAttribute:[NSNumber numberWithFloat:(mean/nbItems)]];
}
这样,每次我在EntityB中设置属性时,都会重新计算平均值,这正是我所需要的。谢谢 一个简单的方法是创建一个持久属性,并使用子属性的平均值更新该属性 下面是一个基于子节点状态设置项目节点(NSManagedObject子类)状态的示例,请注意,在这种情况下,父节点和子节点都属于同一类。计算子级属性值的平均值应该是直截了当的,但请告诉我,我可以发布一个修改版本来说明:
- (void) setStatus:(NSNumber *)status
{
//LOG(@"setStatus called");
[self willChangeValueForKey:@"status"];
[self setPrimitiveStatus:status];
[self didChangeValueForKey:@"status"];
if (self.parent !=nil)
[self.parent updateStatus];
}
- (void)updateStatus
{
// Do nothing if we are on hold
if ([self.status intValue] == 5)
return;
// Ignore if user has set SpecialGroup on it
if ([self.isSpecialGroup boolValue])
return;
self.status = [self getMyStatus];
}
- (NSNumber*)getMyStatus
{
NSMutableArray *statusArray = [[NSMutableArray alloc] init];
for (ProjectNode *child in self.children) {
// Ignore on Holds.
if ([self.status intValue] != 5)
[statusArray addObject:child.status];
}
// Check is all are 0
int result = 0;
BOOL isOneBehind = NO;
BOOL isOneNotStarted = NO;
BOOL isOneStarted = NO;
BOOL isOneCompletedLate = NO;
BOOL isOneCompleted = NO;
for (NSNumber *status in statusArray) {
int v =[status intValue];
if (v == 0)
isOneNotStarted = YES;
if (v == 1)
isOneStarted = YES;
if (v == 2)
isOneBehind = YES;
if (v == 3)
isOneCompleted = YES;
if (v == 4)
isOneCompletedLate = YES;
if (v != 5)
result = MAX(v, result);
}
if (isOneBehind)
return [NSNumber numberWithInt:2];
if (isOneStarted)
return [NSNumber numberWithInt:1];
if (isOneNotStarted) {
if (isOneCompletedLate)
return [NSNumber numberWithInt:4];
else
if (isOneCompleted)
return [NSNumber numberWithInt:1];
else
return [NSNumber numberWithInt:0];
}
if (isOneCompletedLate)
return [NSNumber numberWithInt:4];
return [NSNumber numberWithInt:result];
}
异常是在代码的第一行还是最后一行引发的?它是在执行提取时在提取行引发的:
\u fetchedResultsController=[[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil]当然,duh(我是说我)。当尝试根据子级的数量进行排序时,我遇到以下异常,这表明不允许使用KVC聚合。这并不奇怪,因为您不能指定键路径,只能指定一个键。由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因是:“包含KVC聚合的密钥路径,其中不应该有一个;无法处理子项。@count“一个简单的方法是创建一个持久属性,并用子项属性的平均值更新它。听起来很有希望。我猜覆盖影响该实体(示例中为EntityB)的类别中的该avg的属性的setter可以解决这个问题吗?只要我能够实现,我会让您知道。非常感谢。我接受你的回答是因为你提出的策略。但我也会发布我自己的答案,因为它更接近我在问题中给出的例子。非常感谢。不用担心,很乐意帮忙。