Objective-C- NSPredicate-过滤NSArray包含包含自定义对象的NSArrays的字典

时间:2013-12-23 18:34:13

标签: ios objective-c uitableview uisearchbar nspredicate

在我的应用中,我在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以不同的方式工作,但由于数组名称对于每一个都不同,谓词要么不做任何事情要么崩溃应用程序(无法解析)

3 个答案:

答案 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];

}

}