StuartM
StuartM

Reputation: 6813

Search controller searching an array of dictionaries

I am trying to follow two tutorials on how to implement a search controller for a UITableView. This is all working ok so far the issue I have is with the search/filter itself:

Tutorial links: http://www.appcoda.com/how-to-add-search-bar-uitableview/ http://code-ninja.org/blog/2012/01/08/ios-quick-tip-filtering-a-uitableview-with-a-search-bar/

One of the link suggests the Predicate method, which I can use as follows:

NSPredicate *resultPredicate = [NSPredicate
                                predicateWithFormat:@"SELF contains[cd] %@",
                                searchText];
self.searchResults = [self.fbFriends filteredArrayUsingPredicate:resultPredicate];

The issue with this, is that the above does not take into account that I do actually want to search the self.fbFriends array but I would like to search each dictionary within that array. The array is setup to have a dictionary for each fb friend, including @"id" and @"name". The table displays the names and in alphabetical order - this all works fine.

I would like to be able to search within the dictionaries within the self.fbFriends array and return an array (self.searchResults) that is the filter array of dictionaries.

The second tutorial ops for another route shown below:

for (NSDictionary *friend in self.fbFriends) {
    NSRange textRange = [[friend objectForKey:@"name"]rangeOfString:searchText options:NSCaseInsensitiveSearch];
    if (textRange.location != NSNotFound) {
        [self.searchResults addObject:friend];
    } else {
        [self.searchResults removeObjectIdenticalTo:friend];
    }
}

The problem with this route is that I am not checking that the object already exists in the filtered self.searchResults array therefore continue to add after each character is typed... I am sure this could be solved, but I do not think this is the cleanest method. If the predicate is best, how can I get that to work with the array/dictionary layout detailed above?

EDIT - from answer

self.searchResults = [self.fbFriends filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSDictionary *object, NSDictionary *bindings) {
     //get the value from the dictionary (the name value)
     NSString *name = [object objectForKey:@"name"];
                                                                 //check if the name contains the search string (you can change 
                                                                 //the validation to check if the name starts with 
                                                                 //the search string or ends etc.
    if([name rangeOfString:searchText].location != NSNotFound) {
        return YES;
    }
    return NO;
}]];

Upvotes: 0

Views: 1709

Answers (1)

danypata
danypata

Reputation: 10175

You can use the block form of the predicate something like:

self.searchResult = [self.array filteredArrayUsingPredicate:[NSPredicate 
//since the array contains only dictionaries you can change the 
//type of the object which by default is `id` to NSDictionary
   predicateWithBlock:^BOOL(NSDictionart *object, NSDictionary *bindings) {
        //get the value from the dictionary (the name value)
        NSString *name = [object objectForKey:yourDictionaryNameKey];
        //check if the name contains the search string (you can change 
       //the validation to check if the name starts with 
       //the search string or ends etc.
      if([name rangeOfString:searchString].location != NSNotFound) { 
          return YES
      }
      return NO  
}]];

Also you might have to declare the searchString with the __block identifier.

Upvotes: 3

Related Questions