仅将 NSSortDescriptor 应用于由 NSFetchedResultsController 的 NSPredicate 过滤的实体

Posted

技术标签:

【中文标题】仅将 NSSortDescriptor 应用于由 NSFetchedResultsController 的 NSPredicate 过滤的实体【英文标题】:Only apply NSSortDescriptor to entities filtered by NSPredicate for a NSFetchedResultsController 【发布时间】:2013-11-20 21:02:25 【问题描述】:

对于 TableViewController,我正在创建一个 NSFetchedResultsController。

模型看起来像:EntityA > EntityB。在下面的代码中,关系称为 entityRelationship。 EntityB 有一个 NSNumber 属性,称为属性。

我需要对结果进行过滤和排序。我是这样做的:

predicate = [NSPredicate predicateWithFormat:@"entityRelationship.@count > 0"];
[fetchRequest setPredicate:predicate];
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"entityRelationship.@avg.attribute"
                                             ascending:NO];

基本上,我需要显示所有具有非空 entityRelationship 的实体,并按 entityB 属性的平均值对其进行排序。

显示的代码抛出异常:* 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“-[__NSCFString characterAtIndex:]: Range or index out of bounds”

sortDescriptor 不是仅适用于谓词过滤的结果吗?我怎样才能在一个请求中实现这一目标? (由于这个请求链接到一个 NSFetchedResultsController,我不想先获取然后排序)。

谢谢!

编辑

根据邓肯的回答,我找到了解决方案。我仍然认为发布我的答案是相关的,使用与我的问题相同的示例。

在基于 EntityB 的类别中,我覆盖了属性的设置器。 (我需要知道 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中设置属性时,都会重新计算平均值,这正是我所需要的。谢谢!

【问题讨论】:

异常是在第一行还是最后一行抛出? 执行fetch时抛出,在fetch行:_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil]; 当然,呃(我是说)。尝试根据指示不允许使用 KVC 聚合的子项数量进行排序时,出现以下异常。不足为奇,因为您不能只指定一个 keyPath 一个键。由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“包含 KVC 聚合的密钥路径不应存在;未能处理孩子。@count' 一种简单的方法是创建一个持久性属性并使用子属性的平均值保持更新。 听起来很有希望。我猜想覆盖影响该实体类别中此平均值的属性的设置器(示例中为 EntityB)可以解决问题吗? 【参考方案1】:

一种简单的方法是创建一个持久性属性并使用子属性的平均值对其进行更新。

这是一个根据子节点的状态设置项目节点(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];

【讨论】:

一旦我能实现这一点,我会告诉你的。谢谢! 由于您建议的策略,我接受了您的回答。但我也会发布我自己的答案,因为它更接近我在问题中给出的示例。谢谢! 不用担心,很高兴为您提供帮助。

以上是关于仅将 NSSortDescriptor 应用于由 NSFetchedResultsController 的 NSPredicate 过滤的实体的主要内容,如果未能解决你的问题,请参考以下文章

我可以将自定义令牌规则应用于由 spaCy 中的前缀拆分的令牌吗?

我想将噪声应用于由3D numpy数组描绘的体积

FxCop 中的自定义规则仅适用于由特定类型的方法调用的方法

RubyCocoa将NSSortDescriptor应用于ruby数组。

在带有 iCloud 的 CoreData 驱动应用程序中使用 NSSortDescriptor 和 NSFetchedResultsController 的自定义部分

NSFetchedResultsController 与许多 NSSortDescriptor