2013-12-23 78 views
1

在我的应用程序中,我在UItableView的部分中显示联系人列表。我的数据源是NSMutableArray,其中包含NSDictionaries,其中包含两个自定义对象类型的数组(请参阅下面的debugDescription)。Objective-C- NSPredicate-过滤NSArray包含包含NSArrays自定义对象的字典

第一部分显示联系人组名(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>" 
     ); 
    }, 

UPDATE:按照下面发现这里的评论和信息: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]; 


} 

我可以从A组中筛选出组对象rray,但我得到他们所有人,而不仅仅是以我的searchText字符开头的人。 试图让Predicate以不同的方式工作,但由于数组名称对于其中的每一个都不相同,谓词要么不会做任何事情,要么不会崩溃应用程序(无法解析)

回答

0

有(尽可能我知道)没有直接的方法来将过滤器应用于您的 数据源的“内部阵列”,并返回一个具有相同结构的新数据源数组。

你必须单独过滤自定义对象的每个阵列,使用谓词像

[NSPredicate predicateWithFormat:@"groupName CONTAINS[c] %@", searchText] // for groups 
[NSPredicate predicateWithFormat:@"contactName CONTAINS[c] %@", searchText] // for contacts 

,然后建立一个新的数据源阵列。

+0

不能使它可以运行两个子谓词,然后在主谓语两个子谓词返回大于零个对象要求?由于感冒,我有点头晕,所以我可能是错的。 –

+0

@LeoNatan:'filteredArrayUsingPredicate'返回原始数组的“子数组”,但这里我们需要修改元素的数组。 - 我能想到的唯一选择是将'filterUsingPredicate'应用于内部数组,如果它们是可变的。但是这会修改原始数据源。 - 快点好起来! –

+0

有道理。谢谢! –

0

您可以通过在一个稍微不同的方式接近你的问题使事情变得更容易自己很多:

  • 使用UILocalizedIndexedCollation而不是手动将联系人信息。
  • 将组名称存储在与联系人分开的数组属性中。您可以在表视图数据源部分进行切换以提取正确的数据。
  • 如果您的确实是需要使用谓词来过滤数据,并且无法弄清楚如何使用谓词语法进行操作,请使用NSPredicate + predicateWithBlock:
+0

为我的下一个版本,我希望实施您的方法,它是否适用于以多种语言存储联系人姓名的用户? –

0

这已经有一段时间,但对于它的价值,我终于用下面的方法去: - 两个独立的过滤处理 -the组过滤是非常简单的,因为我有我的过滤一个辞典保持组对象评估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]; 

} 

}