Monday, December 17, 2012

Table Search Display Tutorial

This is what we want to achieve in this tutorial:

A table list with a search bar on top, and when we type on the search bar, the table updates its list.

Prerequisite in learning this tutorial is a knowledge in creating table views. If you still don't know how to make table views, refer to the old tutorials.  (http://iosmadesimple.blogspot.com/2012/10/adding-uitableview-tutorial.html)

1. Create a New Xcode project, choose a Single View Application template.

I'm using the latest Xcode up to date, so you may see a longer UIView in our xib file (for iPhone 5 devices). But if you want the old UIView size, you may change it by choosing Retina 3.5 Full Screen on the Simulated Metrics (right panel of the image above).

2. Look for "Search Bar and Search Display Controller" in Objects Library and drag it to our UIView.


3. Set up the table, the list of items, implementation of the delegate and datasource methods of tableview and everything else. If you have no idea how, follow this tutorial about adding UITableView. (http://iosmadesimple.blogspot.com/2012/10/adding-uitableview-tutorial.html)

4. Add this to your interface header, together with your UITableViewDataSourceUITableViewDelegate:

UISearchDisplayDelegate, UISearchBarDelegate

5. We need to add two more variables:
A boolean variable that will tell us if the user is currently searching;
and a mutable array where we can put the filtered list when the user is searching.

BOOL isSearching;

NSMutableArray *filteredList;

6. Set the boolean variable to NO, and allocate and initialize the filteredList in our viewDidLoad function:
isSearching = NO;
filteredList = [[NSMutableArray alloc] init];

7. Create a method that will add an object to our filteredList according to the string typed by the user.

- (void)filterListForSearchText:(NSString *)searchText
{
    [filteredList removeAllObjects]; //clears the array from all the string objects it might contain from the previous searches
    
    for (NSString *title in list) {
        NSRange nameRange = [title rangeOfString:searchText options:NSCaseInsensitiveSearch];
        if (nameRange.location != NSNotFound) {
            [filteredList addObject:title];
        }
    }
}


8. Implement the search display delegate methods.
#pragma mark - UISearchDisplayControllerDelegate

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
//When the user taps the search bar, this means that the controller will begin searching.
    isSearching = YES;
}

- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
//When the user taps the Cancel Button, or anywhere aside from the view.
    isSearching = NO;
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    [self filterListForSearchText:searchString]; // The method we made in step 7
    
    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
    [self filterListForSearchText:[self.searchDisplayController.searchBar text]]; // The method we made in step 7
    
    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

9. Update our tableview method numOfRows: and cellForRow:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    if (isSearching) { 
        //If the user is searching, use the list in our filteredList array.
        return [filteredList count];
    } else {
        return [list count];
    }

- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    
    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    }
    
    // Configure the cell...
    NSString *title;
    if (isSearching && [filteredList count]) {
        //If the user is searching, use the list in our filteredList array.
        title = [filteredList objectAtIndex:indexPath.row];
    } else {
        title = [list objectAtIndex:indexPath.row];
    }
    
    cell.textLabel.text = title;
    
    return cell;
}

10. Hit Run and your search display controller is done!

Blocks From one Class to Another

One popular scenario in using blocks is when you need to update your view after a web service call is finished.