【问题标题】:Custom NSSortDescriptor on complex object复杂对象上的自定义 NSSortDescriptor
【发布时间】:2012-06-26 07:02:03
【问题描述】:

这是我的第一篇文章,即使我会尽力而为,如果我可能不遵守所有惯例,我深表歉意。我之前一直在 SO 上找到解决问题的方法,但我完全陷入了一个相当复杂的 Cocoa 问题。

我正在尝试对 CoreData 对象列表进行复杂排序。我有一个由 Book 对象组成的目录,它可以是 Saga 的一部分(第一本书及其续集)。简化的结构如下所示:

@interface Book : NSManagedObject
@property (nonatomic, retain) NSString * title;
@property (nonatomic, retain) NSNumber * tomaison; //volume numbering
@property (nonatomic, retain) Saga *fromSaga;

@interface Saga : NSManagedObject
@property (nonatomic, retain) NSString * title;

我正在尝试在我的 CoreData 数据库上执行查询:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:context];

我需要分三步进行排序:

1) 按书籍的流派排序(由于不需要,因此不包含在上面的代码中),执行方式为:

NSSortDescriptor* mainSort = [[NSSortDescriptor alloc] initWithKey:@"ofGenre.title" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];

2) 如果书是 Saga 的一部分,则按 Saga 标题排序

NSSortDescriptor* secondarySort = [[SagaTitleSortDescriptor alloc] initWithKey:@"fromSaga" ascending:YES];

自定义排序描述符的定义位置:

#define NULL_OBJECT(a) ((a) == nil || [(a) isEqual:[NSNull null]])
@interface SagaTitleSortDescriptor : NSSortDescriptor {}
@end
@implementation SagaTitleSortDescriptor
- (id)copyWithZone:(NSZone*)zone
{
    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]])) {
        if (NULL_OBJECT([object2 valueForKeyPath:[self key]])) 
            return NSOrderedSame;
        return NSOrderedDescending;        
    }
    if (NULL_OBJECT([object2 valueForKeyPath:[self key]])) {
        return NSOrderedAscending;
    }
    return [super compareObject:[(Saga*)object1 title] toObject:[(Saga*)object2 title]];
}
@end

3) 如果它是 Saga 的一部分,则按卷编号排序,否则按书名排序。这是我的问题,因为我不知道要发送什么密钥以及要在我的描述符中放入什么(我什至不确定这是否可能)。

NSSortDescriptor* thirdSort = [[SagaTomaisonOrBookTitleSortDescriptor alloc] initWithKey:@"self" ascending:YES];  

到目前为止,我发现@"self" 允许发送被查询的对象,但它似乎不允许查询发送对象内的参数。作为参考,我尝试了一些代码:

- (NSComparisonResult)compareObject:(id)object1 toObject:(id)object2
{
    if (NULL_OBJECT([(Book*)object1 fromSaga]) && NULL_OBJECT([(Book*)object2 fromSaga])) {
        return [super compareObject:[(Book*)object1 title] toObject:[(Book*)object2 title]];
    }
    if (NULL_OBJECT([(Book*)object1 fromSaga])) {
        return NSOrderedDescending;
    }
    if (NULL_OBJECT([(Book*)object2 fromSaga])) {
        return NSOrderedAscending;
    }
    return [super compareObject:[(Book*)object1 tomaison] toObject:[(Book*)object1 tomaison]];
}

知道我能做什么和应该做什么吗?

谢谢!

编辑:最后一行有一个类型

【问题讨论】:

  • 这是 NSFetchRequest 的一部分吗?您使用的是什么核心数据后备存储?如果是 SQL 后端,则不能将基于代码的排序描述符与 NSFetchRequest 一起使用。
  • 它确实是 NSFetchRequest 的一部分,我使用的是标准 CoreData 模型(.xcdatamodel、NSManagedObjectContext 等)。请注意,第二个排序描述符可以完美运行。

标签: ios cocoa core-data nssortdescriptor


【解决方案1】:

如果您不使用基于 SQL 的存储,则可以通过将 self 作为键并将 compare: 作为选择器来执行此操作,然后实现该自定义选择器。也就是说,在你的 book 类上创建一个名为 compare: 的方法,让它完成你所有的逻辑,而不是使用多个排序描述符。

【讨论】:

  • 这很有趣。但是,它似乎也不起作用。我在我的 Book 类中实现了一个自定义选择器(在一个更具体的类别中)并且它崩溃了。我已经通过一些非常简单的测试进行了验证:- (NSComparisonResult)specialCompare:(id)other { return NSOrderedSame; } 在 ViewController 中:NSSortDescriptor* thirdSort = [[NSSortDescriptor alloc] initWithKey:@"self" ascending:YES selector:@selector(specialCompare:)]; 我做错了什么吗?
  • 附加说明:我不能简单地覆盖 Book.h 中的 compare: 方法,因为这不是我比较两本书的唯一地方,其他地方还有其他排序方法
  • 对我来说这看起来不错。崩溃发生在哪里?你得到什么信息?
  • 崩溃发生在[theFetchedResultsController performFetch:nil]; 通话期间。没有消息,不幸的是,无法在自定义 NSSortDescriptor 中调试(或至少,据我所知)、日志或任何内容。
  • 您使用的是基于 SQLLite 的后备存储吗?如果是这样,您应该获取它们(未排序),然后自己对结果数组进行排序。
猜你喜欢
  • 2016-09-13
  • 2015-05-03
  • 1970-01-01
  • 2016-11-22
  • 2017-01-17
  • 1970-01-01
  • 2017-08-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多