自定义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; }];