A “search controller” is the thing behind a
UISearchBar on iOS that is responsible for showing and hiding the “search results” screen (typically a table view) and updating the results in response to changes to the search term, character by character.
Let’s go through the setup of a very simple search controller for an iOS app. It will display a list of Swift keywords in a table and filter them in response to text entered into the search bar.
What’s unexpected about
UISearchController is that you have to install its
searchBar into the view hierarchy. You can’t connect it to an existing
UISearchBar defined in a storyboard.1 If you’re just adding the search bar to the top of a table, like in Apple’s sample code2, you can just make it the
tableHeaderView. But just about any other situation is going to have to deal with auto layout.
We’re going to reserve some space in the UI using a “container” view3. This will show where the search bar will eventually be in the storyboard to give an idea of how it will fit with other UI elements. Also, constraints can be tied to the container view in the storyboard so that none need to be installed in code.
Search Results Controller
The search results controller is just a simple
UITableViewController with each cell displaying a single Swift keyword.
UISearchController must be set up in code and it’s constructor takes a single argument - a
UIViewController which is going to display the search results. Here we pass in a reference to our
searchResultsController stored in a property.
There is little interaction with
UISearchController beyond creating one, configuring it and connecting it to the following:
- the search results controller
Search Results Updater
UISearchResultsUpdating protocol is very simple, but it’s where all the fun happens:
This method is called whenever the text changes in the search bar. The current text can be accessed through the
searchController parameter. Any object can handle these updates.
It’s common to also make the search results controller the
searchResultsUpdater and have it conform to the
UISearchResultsUpdating protocol. That configuration causes the search results controller to update itself with each change to the search term. However, we’re not going that route because of a special case we want to handle: a custom “empty results” view. Attempting to add a subview to a
UITableView is fraught with peril, so we’re not going to do that.
Instead the “main” view controller will be the
searchResultsUpdater and it will pass the current
searchTerm into the search results controller. The search results controller will take care of filtering and return the number of results displayed.
The “main” view controller will use the number of results displayed to determine when to show and hide the “no results” view.
emptyResultsView is defined in the storyboard and initially hidden.
That’s pretty much it. I wanted to provide a simple example because there’s a lot of confusing information out there on how this API works. Web searches are tainted with the old API since the type names are so similar.4
You can find the complete project on GitHub at the URL below:
The only other interesting aspect of this sample project is how the Swift keywords are escaped to serve as enum member values. Sure, it’s easier to store them as strings but where’s the fun in that?
Other Types of Search Results
UISearchController is not coupled with the presentation of the search results, so we are free to use any kind of view controller to handle it. At 360|iDev 2015, @jeremiahgage presented using a UISearchController with a UICollectionView which is a fabulous example especially since
UICollectionView is so highly customizable.
Do yourself a favor and never look at the API for
UISearchDisplayController- it’s deprecated anyway. I’m constantly confusing the two. ↩