NSSortDescriptor 对可能为 nil 的属性进行排序

NSSortDescriptor sorting on properties that could be nil

我有一组报告它们距离的信标,我正在一个项目中工作,该项目具有我无法更改的既定架构,否则我可能可以选择不同的方法。

存在报告其平均距离的信标对象数组。现有代码根据平均距离对信标数组进行排序,存储在名为 _averageDistance 的 属性 中。一切正常,直到离线信标报告 nil _averageDistance 表明它不可用。

当前代码如下:

NSSortDescriptor* sortOnDistance = [NSSortDescriptor sortDescriptorWithKey:@"averageDistance" ascending:YES];
NSArray* sortDescriptors = [NSArray arrayWithObject:sortOnDistance];
NSArray* sortedBeacons = [allBeacons sortedArrayUsingDescriptors:sortDescriptors];

BOOL sameBeacon = NO;
if(![[sortedBeacons firstObject] isEqual:_closestBeacon]){
    _closestBeacon = (PTBeacon*)[sortedBeacons firstObject];
}
else {
    sameBeacon = YES;
}

有没有办法控制在对 NSArray 进行排序时处理 nil 值的方式?谢谢!

我会编写自定义 NSSortDescriptor 来处理您认为合适的 nil 值:

NSSortDescriptor* sortOnDistance = [NSSortDescriptor sortDescriptorWithKey:@"averageDistance"
                                            ascending:YES
                                           comparator:^NSComparisonResult(id obj1, id obj2)  {
                                               if(obj1 == nil){
                                                    //customize here
                                                    return NSOrderedDescending;
                                               }else if(obj2 == nil){
                                                    return NSOrderedAscending;
                                               }else{  
                                                    return [obj1 compare:obj2];}
                                               }];

您可以使用不同的排序方法将不可用的信标强制排到最后:

[allBeacons sortedArrayUsingComparator:^(PTBeacon * firstBeacon, PTBeacon * secondBeacon){
    if( ![firstBeacon averageDistance] ){
        return (NSComparisonResult)NSOrderedAscending;
    }
    else {
        return [[firstBeacon averageDistance] compare:[secondBeacon averageDistance]];
    }
}];

这使得 averageDistancenil 的任何信标比任何其他信标都大,这与当前发生的情况相反。不可用的信标将最终(在它们之间以任意顺序)超过排序数组中的任何其他信标。

或者您可以在排序前过滤数组:

NSPredicate * availabilityPredicate = [NSPredicate predicateWithFormat:@"averageDistance != NIL"];
NSArray * allAvailableBeacons = [allBeacons filteredArrayUsingPredicate:availabilityPredicate];

这将导致 allAvailableBeacons 仅包含 averageDistance 不是 nil 的信标。然后您对该数组而不是原始数组进行排序。