在我的应用中,我在UItableView
中显示了一个联系人列表。我的数据源是NSMutableArray
持有NSDictionaries
,其中包含两个自定义对象类型的数组(请参阅下面的debugDescription
)。
第一部分显示联系人组名称(SNPgroupData.groupName
),其余部分显示按其SNPcontactData.contactName
属性的第一个字母排序的联系人。
这一切都运行良好,当我想在tableView中搜索特定项时,就会出现问题。
是否可以使用NSpredicate
(或其他方法)过滤具有包含(contains[c] %@",searchText?
)搜索字符串属性的任何项目(群组和联系人)?
以下NSArray
是我UItableView
的数据源:
{
Groups = (
"<SNPgroupData: 0x16e5ae80>",
"<SNPgroupData: 0x16d9ff80>"
);
},
{
A = (
"<SNPContactData: 0x16dd5fd0>",
"<SNPContactData: 0x16d8a840>",
"<SNPContactData: 0x16dd68b0>",
"<SNPContactData: 0x16dd7a10>",
"<SNPContactData: 0x16dcef60>",
"<SNPContactData: 0x16d9dc90>",
"<SNPContactData: 0x16dd6950>",
"<SNPContactData: 0x16db5070>",
"<SNPContactData: 0x16d98820>",
"<SNPContactData: 0x16dac810>",
"<SNPContactData: 0x16d8e510>",
"<SNPContactData: 0x16dbf5d0>",
"<SNPContactData: 0x16dcfbd0>"
);
},
{
B = (
"<SNPContactData: 0x16dae7b0>",
"<SNPContactData: 0x16dd6ef0>",
"<SNPContactData: 0x16dd9f90>",
"<SNPContactData: 0x16d8e480>",
"<SNPContactData: 0x16d9c750>",
"<SNPContactData: 0x16d9ba20>",
"<SNPContactData: 0x16d9ba40>",
"<SNPContactData: 0x16dd6e20>"
);
},
{
C = (
"<SNPContactData: 0x16dcf790>"
);
},
更新:按照以下评论和此处发现的信息:How to Predicate through Nested Arrays with Keys,我正在努力做以下事情:
(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
NSLog(@"%@",[self.groupedAppContacts debugDescription]);
self.filteredContacts=self.groupedAppContacts;
NSPredicate *groupNamePredicate = [NSPredicate predicateWithFormat:@"ANY %K.groupName contains[c] %@",@"Groups",searchText]; //this filters out only the group objects but disregards their names
NSPredicate *contactNamePredicate = [NSPredicate predicateWithFormat:@"ANY %K.%K contactName contains[c] %@",searchText]; //this crashes
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:
@[groupNamePredicate, contactNamePredicate]];
[self.filteredContacts filterUsingPredicate:predicate];
}
我能够从数组中过滤出组对象,但我得到了所有这些对象,而不仅仅是以我的searchText字符开头的那些对象。 试图让联系方式Predicate以不同的方式工作,但由于数组名称对于每一个都不同,谓词要么不做任何事情要么崩溃应用程序(无法解析)
答案 0 :(得分:0)
有(据我所知)没有直接的方法将过滤器应用到你的“内部数组” 数据源,并返回相同结构的新数据源数组。
您必须使用
之类的谓词分别过滤每个自定义对象数组[NSPredicate predicateWithFormat:@"groupName CONTAINS[c] %@", searchText] // for groups
[NSPredicate predicateWithFormat:@"contactName CONTAINS[c] %@", searchText] // for contacts
然后构建一个新的数据源数组。
答案 1 :(得分:0)
您可以通过略微不同的方式解决问题,从而使事情变得更轻松:
UILocalizedIndexedCollation
而不是手动分割联系信息。NSPredicate + predicateWithBlock:
。答案 2 :(得分:0)
已经有一段时间但是为了它的价值,我最终选择了以下方法: - 两个独立的过滤流程 - 组过滤相当简单,因为我有一个字典保存组对象,我通过评估groupName属性进行过滤 - 对于联系人,我有多个词典(代表名称以特定字母开头的联系人),我决定检查用户输入的第一个字母,拉相关字典,然后评估contactName。是的,此方法仅适用于以特定搜索查询开头但符合我需求的联系人姓名。
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
if ([searchText isEqualToString:@""]) {
self.showFiltered=NO;
[self.contactsTable reloadData];
}else{
NSLog(@"%@",[self.contactGroups debugDescription]);
NSPredicate *groupNamePredicate = [NSPredicate predicateWithBlock:
^BOOL(id evaluatedObject, NSDictionary *bindings)
{
return [[[evaluatedObject groupName] substringToIndex:searchText.length] isEqualToString:searchText];;
}];
self.filteredContactGroups = [[NSArray alloc]initWithArray:[self.contactGroups filteredArrayUsingPredicate:groupNamePredicate]];
NSLog(@"filtered Names: %@", self.filteredAppContacts);
NSString *firstLetter = [searchText substringToIndex:1];
NSMutableArray *filteredContacts = [[NSMutableArray alloc]init];
for (NSDictionary *letterDictionary in self.groupedAppContacts) {
if ([letterDictionary objectForKey:[firstLetter uppercaseString]]) {
filteredContacts = [letterDictionary objectForKey:[firstLetter uppercaseString]];
}
}
if (filteredContacts.count>1) {
NSPredicate *contactNamePredicate = [NSPredicate predicateWithBlock:
^BOOL(id evaluatedObject, NSDictionary *bindings)
{
return [[[evaluatedObject contactName] substringToIndex:searchText.length+1] caseInsensitiveCompare:searchText];
}];
self.filteredAppContacts = [[NSArray alloc]initWithArray:[filteredContacts filteredArrayUsingPredicate:contactNamePredicate]];
NSLog(@"filtered Names: %@", filteredContacts);
}else{
self.filteredAppContacts = [[NSArray alloc]initWithArray:filteredContacts];
}
self.showFiltered=YES;
[self.contactsTable reloadData];
}
}