Tag Archives: UITableView

How to add a Search Display Controller to a UITableView (in code)

We’ve recently discussed how to deal with a Search Bar and Search Display Controller using Interface Builder. You can however do this in code too. This can be useful if you don’t want to make all the relevant connections in every Storyboard.

This example assumes you have a Table View (self.tableView) to which you’d like to add a Search Bar and Search Display Controller at the top. We do this by utilising the Table View’s tableHeaderView property:

Your View Controller also needs to conform to the UISearchBarDelegate Protocol for this to work properly.

How to create an NSIndexPath and specify its components

On occasion we need to create an NSIndexPath manually, with components we specify (such as a row or a section). There’s a method for that: indexPath:forItem:inSection.

Here’s how you create an indexPath for row 0, section 0:

The method takes two integers. You can even take an existing indexPath, then add or subtract values to the new indexPath, like so:

How to dequeue UITableViewCells

Sometimes Xcode does a bit of magic behind the scenes which I don’t really understand.

Consider this standard table view method to display cells:

Where do we actually ever create a UITableViewCell? All we’re asking here is “do we have reusable ones available” – but if the answer is “no”, then somehow these get created without an error message. Other times (such as when using an overlay table view courtesy of the search display controller) we get an error message.

This brings me to the point that perhaps Xcode and iOS create as well as dequeue cells automatically – but when they don’t, here’s how we can do this manually.

Let’s amend the above code snippet:

Now we properly create a cell should a dequeueable one not be available.

I haven’t had to use this, and the if statement never seems to get called if inserted into the Master/Detail template, yet I find this may be something to keep in mind for future projects.

How to hide (and show) the UISearchBar in a UITableView

If you add a UISearchBar to your table view (see previous article) it’s just sitting there by default. Chances are you’d like to hide it when your table view first loads.

You can do this by adding the following code to your viewWillAppear method:


Now it’s hidden, users make a search, hit cancel… and then it comes back into view. Wouldn’t it be nice if we could hide it again after users are finished with their search? And sure we can! We’re already conforming to the UISearchBarDelegate protocol, so all we need to do is to implement the following method and react to the cancel button:


We could implement the same code as above, or just call the viewWillAppear method again.

Note that you have to set the search bar’s delegate to your class for this to work. Searches are working fine when it’s not set, but to react to the cancel button it needs to be set (either in code or via the Connections Inspector in Interface Builder).

You can find a full demo project on GitHub: Table Search 2013 (updated for iOS 7)

How to create a searchable UITableView

The ingredients for a search function in a UITableView are more involved than just displaying a simple search field. First we need the standard UITableView. Next we need a UISearchBar which can be added to the top of the table view. But displaying the actual search results is something called the UISearchDisplayController.

This process isn’t very well documented from what I could find, so here’s how I did it successfully. Works fine in iOS 6.

For iOS 5 compatibility please see my comment at the end.

This new controller “switches out” the standard table view and overlays a new one (the search display). Since the data for the search view is more or less the same as what was already powering the original table view (only “filtered”), the search view often uses the same data source as the original table view.

Speaking of filtering the original data: this is done with something called a predicate (NSPredicate). First time I’ve heard of this was in regards to Core Data. A predicate is a rather powerful yet mysterious thing and rest assured you don’t need to understand it in order to use it.

Let’s go through this step by step: from creating a standard table view with some dummy data, then adding a search function and slowly making it work.


Creating the Table View

I’ll start with a Single View Application project (with Storyboards and ARC selected), removing the single View Controller from the Storyboard. Delete both ViewController h and m files too.

Next we’ll drag a UITableViewController into the Storyboard. Select the cell and set its reuse identifier to “Cell”. Next we’ll create a new Cocoa Touch Objective-C Class called TableViewController, naturally being a sub class of UITableViewController. Before we do anything else, let’s set this custom class in our Storyboard.

We’ll also create two properties in our h file:

  • an NSArray called allData, holding all our data
  • an NSMutableArray called searchResults which will hold our filtered results

Before we forget, let’s initialize the latter in our viewDidLoad method:

Creating some Dummy Data

Here’s a small method that initializes our data: 24 written out numbers. This could be anything really:

Let’s call this method in our viewDidLoad so it’s ready for use as soon as the app starts:

Populating the Table View

Let’s make our table view show those items: take out the two #warnings and all commented code to make our class a bit more readable. Next set the tableView:numberOfSections to 1 as we wont be dealing with sections here.

The tableView:numberOfRowsInSection needs to be the amount of our allData array, so we’ll make it look like this:

And the final method we need to amend is the tableview:cellForRowAtIndexPath method so that text gets displayed in each cell:

Note that since Xcode 4.6 the template for a new Table View class has changed to incorporate an extremely annoying addition: right after the line with dequeueReusableCellWithIdentifier, we find “forIndexPath:indexPath”. This makes your app crash in iOS 5 and sometimes in iOS 6. Remove it to reflect my code above – you’ll avoid a lot of hair pulling later!

Run the app to see all our values listed as expected.

We’re not dealing with selecting them, but we’ll see next how we can make the view change into search mode.

Bring on the big Search Bar

This is where things get interesting: back in the storyboard, drag a UISearchDisplayController to the very top of your table view, so that it sits above the dummy cell. Switch to Assistant Editor mode and control drag a reference into your h file so we can address this thing.

Notice that when you do this you will only be able to create an outlet to a UISearchBar – that’s fine, it’s part of the UISearchDisplayController. Call it searchBar.

Setting up our Predicate

Back in the TableViewController.m file we need to add a couple of helper methods. The first one is a method called filterData. We will call this repeatedly so a small method will work best for us:

This method will take what’s in our search bar and compare it to our allData array. Matching items are placed into our searchResults array (which we clear out at the beginning of this method). The [cd] statement means we don’t want to know about caSe sEnSitiVity or “diacritics” which are things like the Umlaut Dots above a letter and such.

The great thing for us is that after calling this method, we know how many matches we have and hence how many cells we need to display. We want to call this method every time someone adds a single letter to our search bar. And in order to know when that is, we better conform to the

UISearchBar Delegate Protocol

If we’re the Search Bar’s delegate, then we can implement a method that tells us when our search text changed. This is what we want! Head over to your TableViewController.h file and add the protocol declaration to the top:

Back in the m file add this method, which in turn will call our filterData method:

There’s no need to setup the delegate; since we’ve implemented a Search Display Controller, this has been done for us already.

Dealing with the Search Display Controller

This controller is rather clever: rather than bringing up a modal view or anything visually disruptive, the Search Display Controller “overlays” his own table view above out existing one, dimming the latter out. It’s slick alright – but therefore also a tad confusing. Because out of a sudden, we have TWO table views to deal with.

So when we tell the usual data source methods how many sections, rows and cells we need to display, we need to do so via an if-then statement so see which table view is requesting the data.

We’ll start with the tableView:numberOfRowsInSection method:

Here we ask: if it’s the “normal” table view, show the number of our allData array. If that’s not the case, we’ll be asked by the Search Display Controller. In which case, call the filterData method, then see how many items are, and then count those.

We need to do the same for our cellForRowAtIndexPath method:

Again if the “standard” table view is asking, display an object from the allData. If it’s the other guy, display it from searchResults (by which time we would have just called the filterData method so we’re not calling it again).

One other point of note here is the if(!cell) statement:

Leaving this out makes the table view crash as soon as you hit a letter. For some reason cells don’t automatically create themselves as needed, which works fine in a standard table view. So if there aren’t any, we just create as many as needed.

Full Project Code

You can get the entire project on my repository on GitHub: Table Search 2013


Further Reading

iOS 6 Table View crashes when deployed to iOS 5

Apple have changed the UITableViewController template in iOS 6 a bit. Specifically, when you create a new UITableViewController class, it’s created using something like this (in the cellForRowAtIndexPath method):

When run in iOS 5 the app crashes. The culprit seems to be the addition of forIndexPath:indexPath in this declaration which is only available in iOS 6. To make it work in either iOS version, simply take it out, like so:

The full code from an iOS 5 template is:

How to change a cell’s selection colour

By default, when you touch a cell in a UITableView, it lights up bright blue. You can use this property to change the cell’s selection style in the cellForRowAtIndexPath method:

Possible values are

  • UITableViewCellSelectionStyleGray
  • UITableViewCellSelectionStyleBlue (the default)
  • UITableViewCellSelectionStyleNone

Alternatively you can select the cell in Interface Builder and pick these values from the drop down menu:

Screen Shot 2013-01-11 at 01.05.19

How to create a transparent cell in a UITableView

First we make the cell’s background transparent. Next we create a custom view which we can show behind the cell, like so: