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

给出具有核心数据的字符串的以下NSSortDescriptor

 [NSSortDescriptor sortDescriptorWithKey:@"series" ascending:true selector:@selector(caseInsensitiveCompare:)] 

结果按字母顺序正确排序。 但是,在seriesnil情况下,具有nil值的字符串放在顶部,之后对非nil值进行排序,EG:

 [nil, nil, nil, A, B, C, D...] 

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

NSSortDescriptor和nil值

虽然您无法将自定义选择器与Core Data一起使用,但您可以将NSSortDescriptor子类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 

Swift 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) } }