2013-12-23 75 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]; 

} 

}