ios - 使用空值对 NSArray、NSComparator block 与 NSSortDescriptor 进行排序

标签 ios objective-c sorting nsarray

我一直在使用基于 block 的方法对 NSArray 进行排序...但是,我注意到了一个与排序相关的错误,因此开始调查。

背景:我正在处理 EKReminder 对象的 NSArray,它有一个 creationDate 属性。我想按降序 creationDate 对提醒进行排序(最新的提醒,第一个)。

这是我的以前的代码:

// NSArray* fetchedReminders... contents pulled from reminder calendars...

NSArray* sortedArray = [fetchedReminders sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
    NSDate* first = [(EKReminder*)a creationDate];
    NSDate* second = [(EKReminder*)b creationDate];
    return [second compare:first];
}];

我相信该代码是正确的。但是,我最终在数据库中找到了一些以 null 作为创建日期的提醒。这引入了一个错误 - 结果排序不正确。 null 值既不在开头也不在结尾,并且数组中的 null 似乎与这种比较方法混淆,因为许多提醒都是乱序的。

NSSortDescriptor

因此,我尝试将基于 block 的方法换成 sortedArrayUsingDescriptors。这是当前代码:

// NSArray* fetchedReminders... contents pulled from reminder calendars...

NSSortDescriptor* sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:NO];
NSArray* sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray* sortedArray = [fetchedReminders sortedArrayUsingDescriptors:sortDescriptors];

这有效。

(根据当前数据,101 个提醒,其中 6 个的创建日期为 null,它们都放在末尾。其他提醒的顺序正确)。

问题

首先,我对 sortedArrayUsingComparator 方法有什么不妥吗?

如果不是,是否期望这些不同的方法以不同方式处理 null

无论如何,如果您的数据中可能有 null,这是否会使 NSSortDescriptor 成为首选方法?

最佳答案

您在这里遇到的核心问题是您没有手动处理传递给 sortedArrayUsingComparator: 的 block 中的空值。 .根据调用 block 的值,first可以是nil , second可以是nil , 或者两者都可以是 nil .

发送到 nil 的任何消息返回等效的 0值(例如,返回 float 的方法,当发送到 nil 时返回 0.0f,返回 int 的方法,当发送到 nil 时返回 0,返回对象的方法发送到 nil返回 nil )。这意味着您有以下情况:

这意味着在调用数组中的值时,会返回一些无意义的值(例如 [nil compare:[NSDate date]] 返回 0 ,等同于 NSOrderedSame ,这显然不是真的), 更不用说未定义调用返回的结果了。

实际上,这些无效值被排序到数组中的奇怪位置。如果你有一些定义的行为,如果任一值为 nil 应该发生什么,你会得到一致的行为。

以下代码使排序行为保持一致(并且应该为您提供与上面的排序描述符方法类似的行为):

NSArray* sortedArray = [fetchedReminders sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
    NSDate* first = [(EKReminder*)a creationDate];
    NSDate* second = [(EKReminder*)b creationDate];
    if (!first && !second) {
        // nils have the same relative ordering
        return NSOrderedSame;
    } else if (!first) {
        // second is not nil; send first toward the end of the array
        return NSOrderedDescending;   
    } else if (!second) {
        // first is not nil; send second toward the end of the array
        return NSOrderedAscending;
    } else {
        // Neither is nil; this is valid
        return [second compare:first];
    }
}];

关于ios - 使用空值对 NSArray、NSComparator block 与 NSSortDescriptor 进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35165432/

相关文章:

sorting - 排序数据Hadoop Mapreduce

sorting - 如何反转 "glob"标志选项提供的 toctree 的顺序?

android - 如果 Parse 云数据服务失败会怎样?

ios - 在后台使用 iBeacon 或 CoreBluetooth 识别 iOS 设备

ios - MBprogressHUD 未按预期显示

objective-c - UIImagePickerControllerMediaURL 对于照片总是 nil

ios - 在 Facebook iOS SDK 中将某些权限更改为强制性

iphone - 获取 iphone objective-c 上已安装应用程序的列表

iphone - 创建一个类以从 Web 服务上的异步调用返回数据

c++ - 使用 qsort() 进行稳定排序?