控制NSSortDescriptor在Core Data中对nil值进行排序的方式

mat*_*ven 8 core-data objective-c ios

给出以下NSSortDescriptor有关Core Data的字符串:

[NSSortDescriptor sortDescriptorWithKey:@"series" ascending:true selector:@selector(caseInsensitiveCompare:)]
Run Code Online (Sandbox Code Playgroud)

结果按字母顺序正确排序.然而,在其中的实例seriesnil,使用字符串nil值放置在顶部,具有非零值被排序之后,EG:

[nil, nil, nil, A, B, C, D...]
Run Code Online (Sandbox Code Playgroud)

有没有办法控制这种行为?核心数据不允许自定义选择器.这是我的一个类似的问题(但不是解决Core Data的限制):

NSSortDescriptor和nil值

mem*_*ons 9

虽然您不能将自定义选择器与Core Data一起使用,但您可以子类化NSSortDescriptor以更改默认行为.这样的事情应该有效:

#define NULL_OBJECT(a) ((a) == nil || [(a) isEqual:[NSNull null]])

@interface NilsLastSortDescriptor : NSSortDescriptor {}
@end

@implementation NilsLastSortDescriptor

- (id)copyWithZone:(NSZone*)zone
{
    return [[[self class] alloc] initWithKey:[self key] 
                           ascending:[self ascending] selector:[self selector]];
}

- (id)reversedSortDescriptor
{
    return [[[self class] alloc] initWithKey:[self key] 
                           ascending:![self ascending] selector:[self selector]];
}

- (NSComparisonResult)compareObject:(id)object1 toObject:(id)object2 
{
    if (NULL_OBJECT([object1 valueForKeyPath:[self key]]) && 
        NULL_OBJECT([object2 valueForKeyPath:[self key]]))
        return NSOrderedSame;

    if (NULL_OBJECT([object1 valueForKeyPath:[self key]]))
        return NSOrderedDescending;

    if (NULL_OBJECT([object2 valueForKeyPath:[self key]]))
        return NSOrderedAscending;

    return [super compareObject:object1 toObject:object2];
}

@end
Run Code Online (Sandbox Code Playgroud)

  • 当在获取的结果控制器中使用时,这种方法对我不起作用。我怀疑在这种情况下 CoreData 将排序描述符转换为 SQL 查询,从不调用 compareObject: (2认同)

net*_*tbe 6

斯威夫特 4.1 版本:

class NilsLastSortDescriptor: NSSortDescriptor {

    override func copy(with zone: NSZone? = nil) -> Any {
        return NilsLastSortDescriptor(key: self.key, ascending: self.ascending, selector: self.selector)
    }

    override var reversedSortDescriptor: Any {
        return NilsLastSortDescriptor(key: self.key, ascending: !self.ascending, selector: self.selector)
    }

    override func compare(_ object1: Any, to object2: Any) -> ComparisonResult {


        if (object1 as AnyObject).value(forKey: self.key!) == nil && (object2 as AnyObject).value(forKey: self.key!) == nil {
            return .orderedSame
        }

        if (object1 as AnyObject).value(forKey: self.key!) == nil {
            return .orderedDescending
        }
        if (object2 as AnyObject).value(forKey: self.key!) == nil {
            return .orderedAscending
        }

        return super.compare(object1, to: object2)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这似乎有效,但正如@joel.d 所提到的,`NSFetchedResultsController` 似乎并不关心它。这是有问题的:) 关于如何让 FRC 使用它的任何想法? (2认同)