Step 1: Add a UISearchBar to your UITableView and create an outlet for it.

Step 2: Add properties for the array of all the table data, and the array of filtered table data.
@property (strong, nonatomic) NSMutableArray* allTableData; @property (strong, nonatomic) NSMutableArray* filteredTableData;
Step 3: Assign your search bar’s delegate to your controller class.
-(void)viewDidLoad { // ...Do initialization stuff here... searchBar.delegate = (id)self; }
Step 4: Implement the searchBar:textDidChange: method from the UISearchBarDelegate protocol. This will let you filter your list as you type. If you want to filter when the search button is clicked, use the searchBarSearchButtonClicked: method instead.
In this example, we are searching through a list of foods with names and descriptions to see if the match the search text. If they do, we add them to our NSMutableArray containing our filtered foods. We also set a flag that indicates whether or not we are currently filtering the list.
-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)text { if(text.length == 0) { isFiltered = FALSE; } else { isFiltered = true; filteredTableData = [[NSMutableArray alloc] init]; for (Food* food in allTableData) { NSRange nameRange = [food.name rangeOfString:text options:NSCaseInsensitiveSearch]; NSRange descriptionRange = [food.description rangeOfString:text options:NSCaseInsensitiveSearch]; if(nameRange.location != NSNotFound || descriptionRange.location != NSNotFound) { [filteredTableData addObject:food]; } } } [self.tableView reloadData]; }
Step 5: Modify our other UITableViewController methods to make them aware of the isFiltering flag, and to use the correct list depending on whether or not we are filtering.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { int rowCount; if(self.isFiltered) rowCount = filteredTableData.count; else rowCount = allTableData.count; return rowCount; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; Food* food; if(isFiltered) food = [filteredTableData objectAtIndex:indexPath.row]; else food = [allTableData objectAtIndex:indexPath.row]; // ... Set up the cell here...; return cell; }
Voila! You now have a UITableView that can be filtered using a UISearchBar.
Thanks for the tutorial. I tried recreating this and had one problem. I’m using a “Custom” cell through iOS5 storyboarding. The problem I see is that when getting back items from my filtered array the custom UITableViewCell comes back as null. In iOS5 I understand you should only have to get a cell via dequieReusableCell and not explicity init a cell. However when the search in the search bar successfully matches the cell comes back as null. I’m not sure how I can manually init my cell with the custom style. Any ideas?
Here’s a snippet from my cellForRowAtIndexPath method.
ItemCell *cell = (ItemCell *)[tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
self.searchBar.tableView.
if (cell == nil){
NSLog(@”Why is this happening when I get a successfull match from the search bar?”);
}
This causes the following error :
Assertion failure in -[UISearchResultsTableView _createPreparedCellForGlobalRow:withIndexPath
*** Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:’
Pingback: ios5 UISearchBar to filter tableview causes Assertion error with a null cell
Hey imran, thanks for the comment.
Using custom cells while filtering is working for me. as long as I make sure to set the cell’s identifier in my storyboard, and pass that identifier to dequeueReusableCellWithIdentifier:
static NSString* CellIdentifier = @”MyCustomCellIdentifier”;
UITableViewCell* cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
And if you have a custom ItemCell class, you should just have to set that as the Custom Class in your cell’s Identity Inspector in your storyboard.
If you’re already doing that, then I’m afraid I have no idea why it wouldn’t be working!
Hey Marty, thanks for the quick reply. I figured out my problem. I had setup my controller hierarchy incorrectly ( I wanted a navigation controller inside a tab controller ). Anyways, by fixing that problem everything works. Thanks for the help!
That’s great to hear, thanks for the update!
Hello, I was trying to make the searchBar…But as you didn’t make the whole script I got confused.
Can you release the entire project or just say which are the types of the variables, text, food…
I coudn’t understand the Step 4…that’s why I got confused…
I don’t know what kind of variables I’ll need for that or what I should attribute for that variables…
Can you give me a hand? Thanks.
Hey, thanks for the comment. I am currently on the road but when I get back I can put up the entire project.
The Food class is just a simple class with a name and a description property. In step 4, the code searches through all the Food objects to find the ones whose name and/or description match the search text.
Pingback: Filtering a UITableView with a search bar – Now With a Sample Project! | App Per Month
Thanks for the tutorial. It was a great help implementing search in my tableview!
Great tutorial. Thanks.
Hi thanks alot for this tutorial it was exactly what I was looking for and I have a question how can I remove the keyboard when I hit search ? I know I should use the [searchBar resignFirstResponder]; but where should I put it ?
Another question is it possible to return the main list if the user deleted whats inside the search bar ??
Again Thx alot for this tutorial
-(void) searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
}
The code provided above is already handling that in the textdidchange. When the search bar text box length is 0, it sets isFiltered to False. Then it reloads the tableview.
This tutorial was nice, but I have a request. Can anyone show me how to use the search bar to select and scroll to the results? I have an array setup with Serial#. I would like to search for the serial number (i.e. 459) and it high light the closest serial number (i.e. 500), and scroll to that cell in the tableview.
I am at a loss and just really getting into this – so all help will be appreciated greatly.
Hey there!
Well, I thought this would be easy, but I can’t seen to get the row to actually select.
Here’s what I did so far:
-Loop through for your items to find the index of the item with a serial number closest to the one you are searching for. Store this in a variable called index.
-Select the row, using the following code:
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:index inSection:0];
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionTop];
This scrolls to the correct row, but it doesn’t seem to actually select it. The same code works perfectly if you do it in, for example, viewDidAppear, so I think that the problem is caused by doing it in -(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)text. I will have to do a bit more investigation to figure out why selection isn’t working in this case.
Marty, thanks! I just got in town, so I will give this a shot.
OK, maybe I am missing something. I could not get any of this to work – maybe it is the rookie showing. Can you elaborate more or email me an example of the code you have working?