【问题标题】:Sorting core data position changes with sort descriptors for iPhone使用 iPhone 的排序描述符对核心数据位置更改进行排序
【发布时间】:2011-09-25 23:35:44
【问题描述】:

我有一个具有两个属性的 CoreData 实体。一个称为“位置”,另一个称为“位置变化”。它们都是整数,其中 position 属性是当前位置,而 positionChange 是前一个位置和新位置之间的差异。这意味着 positionChange 可以为负数。

现在我想按 positionChange 排序。但我希望它忽略负值。目前我正在对其进行降序排序,这将给出结果:2、1、0、-1、-2。 但我正在寻找的是得到这个结果:2、-2、1、-1、0。

关于如何使用排序描述符解决此问题的任何想法?


编辑

我有 2 个类,一个称为 DataManager,另一个包含我的 NSNumber 类别(positionChange 是 NSNumber 类型)。

在 DataManager 中,我有一个名为 'fetchData:' 的方法,我在其中使用排序描述符执行获取请求:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Entity" inManagedObjectContext:managedObjectContext];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"positionChange" ascending:NO selector:@selector(comparePositionChange:)];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];

我正在对请求做更多的事情,但这对这个问题没有意义。

我的 NSNumber 类别应该与您发布的类别完全相同: 在 .h 中:

@interface NSNumber (AbsoluteValueSort)
- (NSComparisonResult)comparePositionChange:(NSNumber *)otherNumber;
@end

在 .m 中:

@implementation NSNumber (AbsoluteValueSort)

- (NSComparisonResult)comparePositionChange:(NSNumber *)otherNumber
{
    return [[NSNumber numberWithFloat:fabs([self floatValue])] compare:[NSNumber numberWithFloat:fabs([otherNumber floatValue])]];
}

@end

当我在我的 DataManager 对象上调用 fetchData 时,我得到了这个错误:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'unsupported NSSortDescriptor selector: comparePositionChange:'

对可能的情况有什么想法吗?我已将我的 NSNumber 类别头文件包含在我的 DataManager 类中。

【问题讨论】:

  • 你能在模型中添加一个absolutePositionChange 字段并用abs(positionChange) 填充它(在positionChange 的设置器中,如果有的话)?您可以在排序描述符中使用该字段。

标签: iphone objective-c sorting core-data nssortdescriptor


【解决方案1】:

试试这个,假设你的 positionChange 是一个 NSNumber:

@interface NSNumber (AbsoluteValueSort)

-(NSComparisonResult) comparePositionChange:(NSNumber *)otherNumber;

@end

接着是:

@implementation NSNumber (AbsoluteValueSort)

-(NSComparisonResult) comparePositionChange:(NSNumber *)otherNumber
{
    return [[NSNumber numberWithFloat: fabs([self floatValue])] compare:[NSNumber numberWithFloat: fabs([otherNumber floatValue])]];
}

@end

然后这样做:

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"positionChange" ascending:NO selector:@selector(comparePositionChange:)];

并使用该描述符进行排序。如果你想让 -2 总是在 2 之后,或者 5 总是在 -5 之后,你可以修改 comparePositionChange: 以在一个数字是另一个数字的负数的情况下返回 NSOrderedAscending。

【讨论】:

  • 对象之间可以调用category方法吗?我的意思是我的排序描述符位于与 NSNumber 类别不同的​​类中。使用上面的示例调用 comparePositionChange: 将不起作用。你明白我的意思了吗?
  • 只需包含任何包含 NSNumber 类别的文件,它应该可以工作。该类别不在任何类别中。
  • 类别在 NSNumber 类中。用您的示例调用它意味着该类别是在 NSSortDescriptor 类中实现的。否则应用程序将因 NSInvalidArgumentException 而崩溃,原因是:“不支持的选择器”。在这种情况下,简单的包含将不起作用。除非我做错了什么。您是否测试过您的解决方案?
  • 我使用排序描述符对 .m 文件中已填充的对象数组进行排序,类别在其 .h 文件中。有效。 sortDescriptorWithKey:ascending:selector: 的文档说“选择器必须指定由 keyPath 标识的属性值实现的方法。”所以它需要一个由 NSNumber 实现的方法,而不是 NSSortDescriptor。
  • 嘿,我已经编辑了我的问题。不允许发布这么长的帖子或发布新的答案。你能看看,看看你是否能发现任何错误?谢谢!
【解决方案2】:

代码失败并出现unsupported NSSortDescriptor selector 错误的原因是您正在使用 SQLite 数据存储并尝试使用 Cocoa 方法作为排序描述符。使用 SQLite 存储,排序描述符被即时翻译成 SQL,排序由 SQLite 完成。这确实有助于提高性能,但这也意味着排序是在您的自定义比较方法不存在的非 Cocoa 环境中完成的。像这样的排序仅适用于常见的已知方法,不适用于任意 Cocoa 代码。

一个简单的解决方法是在不排序的情况下进行提取,获取结果数组,然后对其进行排序。可以使用任何你想要的 Cocoa 方法对数组进行排序,所以 med200 的类别在那里应该很有用。

如果您的数据集不是很大,您也可以从 SQLite 数据存储更改为二进制存储。

【讨论】:

    猜你喜欢
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多