Objective c NSSortDescriptor问题
我正在制作一个通讯录应用程序,从通讯录中提取姓名,并将其存储在核心数据中,然后使用Objective c NSSortDescriptor问题,objective-c,xcode,core-data,nsfetchedresultscontroller,Objective C,Xcode,Core Data,Nsfetchedresultscontroller,我正在制作一个通讯录应用程序,从通讯录中提取姓名,并将其存储在核心数据中,然后使用NSFetchedResultsController将姓名显示在表格上。然而,出现的第一个索引和部分是字母表。但我想像在本机联系人应用程序中那样做,即#索引最终应该出现。 我使用了以下传感器描述程序: sortDescriptor=[[NSSortDescriptor alloc]initWithKey:@“全名”升序:是] 这里的“全名”是核心数据中的键,它由名字和姓氏连接而成。 节标识符是“全名”的第一个字母如
NSFetchedResultsController将姓名显示在表格上。然而,
出现的第一个索引和部分是字母表。但我想像在本机联系人应用程序中那样做,即#索引最终应该出现。我使用了以下
传感器描述程序
:
sortDescriptor=[[NSSortDescriptor alloc]initWithKey:@“全名”升序:是]
这里的“全名”是核心数据中的键
,它由名字和姓氏连接而成。
节标识符是“全名”的第一个字母如果fullName
不是以字母开头,则其节标识符是#。我搜索过它,并在
传感器描述器
比较器中使用了NSDiacriticInsensitiveSearch
,但它不起作用。如果有人有任何想法,请告诉我
下面是我的代码:
NSString *special = @"\uE000";
if ([[self sectionName:contactName] isEqualToString:@"#"]) {
sortName = [special stringByAppendingString:contactName];
}
else{
sortName = contactName;
}
[newContact setValue:[self sectionIdentifier:sortName] forKey:@"sectionIdentifier"];
[newContact setValue:sortName forKey:@"sortName"];
下面是排序描述符:
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"sortName" ascending:YES];
[self-sectionIdentifier:sortName]
如果sortName以非字母开头,则此方法返回#,否则返回其开始时的字母
newContact是实体的对象。您可以执行以下操作:
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"fullName" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
请确保它不会影响您的性能。您可以尝试编写自己的比较器函数 假设它正在对ManagedObject进行排序,并且它们都以全名作为字段,那么下面的内容可能会有所帮助
[[NSSortDescriptor alloc] initWithKey:@"FullName" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
return [[obj1 objectForKey:@"fullName"] compare:[obj2 objectForKey:@"fullName"] options:NSCaseInsensitiveSearch];
}];
这样做的好处是,您还可以为每次比较编写NSLog,并查看发生了什么。您可以将结果分成两个数组,一个以字母字符开头,另一个不以字母字符开头。然后把两者加在一起。假设您从一个名为
results
的托管对象数组开始:
//Create the sort descriptor array
NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey:@"fullName" ascending:YES];
NSArray *descriptors = [NSArray arrayWithObject:sd];
//Create a sorted array of objects where fullName starts with an alpha character
//using a Regex
NSPredicate *pred = [NSPredicate predicateWithFormat:@"fullName MATCHES '^[a-zA-Z].*'"];
NSArray *alpha = [[results filteredArrayUsingPredicate:pred] sortedArrayUsingDescriptors:descriptors];
//Now use the alpha array to create an array of objects where the fullName does not
//start with an alpha character
NSMutableArray *nonAlpha = [results mutableCopy];
[nonAlpha removeObjectsInArray:alpha];
[nonAlpha sortUsingDescriptors:descriptors];
//Now put them back together again
NSArray *sortedResults = [alpha arrayByAddingObjectsFromArray:nonAlpha];
//And if you're not using ARC!
[nonAlpha release];
您可以在实体中存储一个附加属性
sortName
,如果名称以字母开头,则该属性为fullName
,否则为fullName
<代码>是一个固定字符,它比所有字母都“大”。比如说
NSString *special = @"\uE000";
if ("fullName starts with letter")
sortName = fullName;
else
sortName = [special stringByAppendingString:fullName];
现在可以根据sortName
进行排序,如果sortName
以特殊字符开头,则节标识符将为“#”
缺点是您必须存储一个附加属性,优点是您可以继续使用“获取结果”控制器(它只能使用持久属性进行排序)
更新:实际上可以轻松一点
创建新条目时,如果名称为字母,则将sectionIdentifier
设置为名称的第一个字符,否则设置为特殊字符:
NSString *special = @"\uE000";
if ([[NSCharacterSet letterCharacterSet] characterIsMember:[contact.contactName characterAtIndex:0]]) {
contact.sectionIdentifier = [contact.contactName substringToIndex:1];
} else {
contact.sectionIdentifier = special;
}
获取的结果控制器使用sectionIdentifier
对节进行分组和排序。每个部分中的条目按contactName
排序:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Contact"];
NSSortDescriptor *sort1 = [NSSortDescriptor sortDescriptorWithKey:@"sectionIdentifier"
ascending:YES selector:@selector(localizedStandardCompare:)];
NSSortDescriptor *sort2 = [NSSortDescriptor sortDescriptorWithKey:@"contactName"
ascending:YES selector:@selector(localizedStandardCompare:)];
[request setSortDescriptors:@[sort1, sort2]];
self.frc = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.context
sectionNameKeyPath:@"sectionIdentifier"
cacheName:nil];
所有非字母条目现在都分组在最后一节中。最后一步是为最后一节显示正确的节标题#
:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.frc sections] objectAtIndex:section];
NSString *title = [sectionInfo name];
if ([title isEqualToString:special])
title = @"#";
return title;
}
-(NSString*)表视图:(UITableView*)表视图标题标题标题部分:(NSInteger)部分{
id sectionInfo=[[self.frc sections]objectAtIndex:section];
NSString*标题=[sectionInfo名称];
if([标题IsequalString:特殊])
标题=@“#”;
返回标题;
}
我尝试了您的方法,但它没有返回正确的节名和名称index@user1632153:你能把你的代码(或简化的示例项目)放在我可以下载的地方吗?我会尝试找出一个解决方案。@user1632153:请查看我的更新答案。我自己测试过,它似乎很有效,所以我希望它能对您有所帮助。@Martin R我自己的测试表明,tableView:titleForHeaderInSection:
方法在NSFetchedResultsController
初始化为非nilsectionNameKeyPath
时根本不会被调用。因此,这个特殊字符不会被#替换。@JohnTopley:我不能确认,它在我的测试项目中(使用sectionNameKeyPath)起了作用。也许您有一个优先的viewForHeaderInSection
方法?使用此方法会导致应用程序崩溃这是在调试器中提供的:不支持的NSSortDescriptor(不支持比较器块)