Reputation: 535
So I'm currently listening to a text change from the searchBar:
-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)searchText
{
[self filterContentForSearchText:searchText];
}
I want to design a method filterContentForsearchText
such that it automatically filters through my UITableView as I type.
The problem I'm having is that my UITableView is complicated. It has multiple sections with multiple fields. It's basically an contact/address book that is an array of arrays that holds contact objects.
CustomContact *con = [contacts[section_of_contact] allValues][0][x]
where x is a specific row in that section returns a CustomContact "con" that has properties like con.fullName
.
The UITableView currently displays fullNames of contacts in separate sections. How can I filter through this structure of an array/UITableView as I type using my UISearchBar
?
Here's how the table is filled:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
BrowseContactCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BROWSECELL"];
CustomContact *thisContact = [self.contacts[indexPath.section] allValues][0][indexPath.row];
cell.labelName.text = thisContact.fullName;
return cell;
}
Upvotes: 2
Views: 4068
Reputation: 706
I also created an address-book with sections (an array of arrays), so I'll just post my solution, which is however not my own solution (I somewhere found it here on stackoverflow some time ago):
In your UITableViewController
subclass just add the following two UISearchDisplayDelegate
methods (link to the api reference) and the "custom" method filterContentForSearchText
to filter through your array. For better understanding, please read my comments in the code blocks. Further questions or ideas for improvement are always welcome.
#pragma mark - search Display Controller Delegate
- (BOOL) searchDisplayController : (UISearchDisplayController *) controller
shouldReloadTableForSearchString : (NSString *) searchString {
[self filterContentForSearchText : searchString
scope : [[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex : [self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
return YES;
}
#pragma mark - Search Filter
- (void) filterContentForSearchText : (NSString*) searchText
scope : (NSString*) scope {
// Here, instead of "lastName" or "firstName" just type your "fullName" a.s.o.
// I have also a custom NSObject subclass like your CustomContact that holds
//these strings like con.firstName or con.lastName
NSPredicate* resultPredicate = [NSPredicate predicateWithFormat : @" (lastName beginswith %@) OR (firstName beginsWith %@)", searchText, searchText];
// For this method, you just don't need to take your partitioned and
// somehow complicated contacts array (the array of arrays).
// Instead, just take an array that holds all your CustomContacts (unsorted):
NSArray* contactsArray = // here, get your unsorted contacts array from your data base or somewhere else you have stored your contacts;
// _searchResults is a private NSArray property, declared in this .m-file
// you will need this later (see below) in two of your UITableViewDataSource-methods:
_searchResults = [contactsArray filteredArrayUsingPredicate : resultPredicate];
// this is just for testing, if your search-Filter is working properly.
// Just remove it if you don't need it anymore
if (_searchResults.count == 0) {
NSLog(@" -> No Results (If that is wrong: try using simulator keyboard for testing!)");
} else {
NSLog(@" -> Number of search Results: %d", searchResults.count);
}
}
Now, you need to do some changes to your following three UITableViewDataSource
-methods:
Note: the searchResultsTableView is also loaded with the normal common data source methods that are usually called to fill your (sectioned address-book-)tableView:
1.
- (NSInteger) numberOfSectionsInTableView : (UITableView *) tableView
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
// in our searchTableView we don't need to show the sections with headers
return 1;
}
else {
return [[[UILocalizedIndexedCollation currentCollation] sectionTitles] count];
}
}
2.
- (NSInteger) tableView : (UITableView *) tableView
numberOfRowsInSection : (NSInteger) section {
if (tableView == self.searchDisplayController.searchResultsTableView) {
// return number of search results
return [_searchResults count];
} else {
// return count of the array that belongs to that section
// here, put (or just let it there like before) your
// [contacts[section] allValues][count]
return [[currentMNFaces objectAtIndex : section] count];
}
}
3.
- (UITableViewCell*) tableView : (UITableView *) tableView
cellForRowAtIndexPath : (NSIndexPath *) indexPath {
BrowseContactCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BROWSECELL"];
CustomContact *thisContact = nil;
// after loading your (custom) UITableViewCell
// you probably might load your object that will be put into the
// labels of that tableCell.
// This is the point, where you need to take care if this is your
// address-book tableView that is loaded, or your searchTable:
// load object...
if (tableView == self.searchDisplayController.searchResultsTableView) {
// from search list
faceAtIndex = [self->searchResults objectAtIndex: indexPath.row];
} else {
// from your contacts list
contactAtIndex = [self.contacts[indexPath.section] allValues][0][indexPath.row];
}
}
Hope that works for you.
Upvotes: 4