Reputation: 6813
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
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