自定义select器用于NSSortDescriptor和NSFetchedResultsController

我遇到了一些麻烦,我想知道是否有人可以提供一些指导。

我试图按照以下顺序创build节标题:[“推”,“忙”,“完成”,“取消”]。

不幸的是,这个顺序不能用一个简单的“上升是/否”实现…我必须添加一个自定义的比较select器…像这样的东西..:

**“国家”映射到[“推”,“忙”,“完成”,“取消”]

NSSortDescriptor *sortStates = [NSSortDescriptor sortDescriptorWithKey:@"states" ascending:NO selector:@selector(compareCustom:)]; 

因此,我实现了一个“compareCustom”…但事实certificate,我不能实现一个自定义的分拣机,如下面的exception结果:

***终止应用程序由于未捕获的exception“NSInvalidArgumentException”,原因:“不支持的NSSortDescriptorselect器:compareCustom:”

作为参考,sortDate由以下实现:

 request.sortDescriptors = @[sortStates] self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:@"states" cacheName:nil]; 

所以看起来我不能实现一个返回NSComparisonResult的compareCustom? 我觉得应该有可能..但我无法弄清楚如何。 如果有人能提供一些build议,我会非常感激!

另外供参考,这里是我的“compareCustom”方法

 -(NSComparisonResult)compareCustom:(NSString *)anotherState { if ([(NSString *)self isEqualToString:@"Push"] && [anotherState isEqualToString:@"Canceled"]) { return NSOrderedDescending; } else if ([(NSString *)self isEqualToString:@"Push"] && [anotherState isEqualToString:@"Busy"]) { return NSOrderedDescending; } else if ([(NSString *)self isEqualToString:@"Push"] && [anotherState isEqualToString:@"Finished"]) { return NSOrderedDescending; } else if ([(NSString *)self isEqualToString:@"Push"] && [anotherState isEqualToString:@"Push"]) { return NSOrderedSame; } else if ([(NSString *)self isEqualToString:@"Finished"] && [anotherState isEqualToString:@"Canceled"]) { return NSOrderedDescending; } else if ([(NSString *)self isEqualToString:@"Finished"] && [anotherState isEqualToString:@"Busy"]) { return NSOrderedAscending; } else if ([(NSString *)self isEqualToString:@"Finished"] && [anotherState isEqualToString:@"Finished"]) { return NSOrderedSame; } else if ([(NSString *)self isEqualToString:@"Finished"] && [anotherState isEqualToString:@"Push"]) { return NSOrderedAscending; } else if ([(NSString *)self isEqualToString:@"Busy"] && [anotherState isEqualToString:@"Finished"]) { return NSOrderedDescending; } else if ([(NSString *)self isEqualToString:@"Busy"] && [anotherState isEqualToString:@"Canceled"]) { return NSOrderedDescending; } else if ([(NSString *)self isEqualToString:@"Busy"] && [anotherState isEqualToString:@"Busy"]) { return NSOrderedSame; } else if ([(NSString *)self isEqualToString:@"Busy"] && [anotherState isEqualToString:@"Push"]) { return NSOrderedAscending; } else { return NSOrderedSame; } } 

根据文档自定义sorting不适用于SQLite持久性存储:

另一方面,SQL存储将谓词和sorting描述符编译为SQL,并在数据库本身中评估结果。 这主要是为了性能,但这意味着评估发生在非Cocoa环境中,所以依赖于Cocoa的sorting描述符(或谓词)无法工作。 支持的sortingselect器是compare:和caseInsensitiveCompare:,localizedCompare:,localizedCaseInsensitiveCompare :,和localizedStandardCompare:(后者是类似Finder的sorting,大多数人应该使用大部分时间)。 另外,您不能使用SQLite存储对瞬态属性进行sorting。

所以看起来你不能简单地强制NSFetchedResultsController以非字母顺序显示部分。

但是你可以使用一个解决方法。 将整数types的附加持久属性添加到您的实体(我们称之为sectionOrder )。 根据states属性来设置它的值(所以对于"Push"它将是0,对于"Busy"等等将是1)。例如,你可以在awakeFromInsert方法中做到这一点。

然后使用@"sectionOrder"作为sectionNameKeyPath和sorting描述符中的keypath。 你可以使用这个UITableViewDataSource方法将节标题设置为“Push”,“Busy”等:

 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { id <NSFetchedResultsSectionInfo> sectionInfo = [[self.controller sections] objectAtIndex:section]; return [sectionInfo.objects.firstObject name]; } 

感谢这个优秀的答案 。

您正在使用的NSSortDescriptor构造函数尝试调用名为@"states"的属性上的对象的指定select器。 我不确定这个值是什么,但是看起来他们可能是基于你所看到的错误的NSSortDescriptor对象。

不是试图在可能存在或不存在的对象上findselect器,而是使用块构造器:

你也应该考虑用整数或者其他东西来重写你的比较,

 static NSArray *stateOrder = @[@"Push", @"Busy", @"Finished", @"Cancelled"]; NSSortDescriptor *sortStates = [NSSortDescriptor sortDescriptorWithKey:@"states" ascending:NO comparator:^(id obj1, id obj2) { NSInteger state1 = [stateOrder indexOfObject:obj1]; NSInteger state2 = [stateOrder indexOfObject:obj2]; if (state1 < state2) { return (NSComparisonResult)NSOrderedAscending; } else if (state1 > state2) { return (NSComparisonResult)NSOrderedDescending; } return (NSComparisonResult)NSOrderedSame; }];