UISearchController Tutorial: Getting Started

In this tutorial, you’ll build a searchable Candy app based on a standard table view. You’ll add table view search capability, dynamic filtering and an optional scope bar using UISearchController, UISearchBar and friends. By Lorenzo Boaro.

Leave a rating/review
Download materials
Save for later
Share
Update note: Lorenzo Boaro updated this tutorial to Xcode 11, Swift 5 and iOS 13. Tom Elliott wrote the original.

Scrolling through massive lists of items can be a slow and frustrating process for users. When dealing with large datasets, it’s vitally important to let the user search for specific items. UIKit includes UISearchBar, which seamlessly integrates with UINavigationItem via a UISearchController and allows for quick, responsive filtering of information.

In this tutorial, you’ll build a searchable Candy app based on a standard table view. You’ll add table view search capability, dynamic filtering and an optional scope bar, all while taking advantage of UISearchController. In the end, you’ll know how to make your apps much more user-friendly and how to satisfy your users’ urgent demands.

Ready for some sugar-coated search results? Read on.

Getting Started

Start by downloading the starter project using the Download Materials button at the top or bottom of this tutorial. Once it’s downloaded, open CandySearch.xcodeproj in Xcode.

To keep you focused, the starter project has everything unrelated to searching and filtering already set up for you.

Open Main.storyboard and look at the view controllers contained within:

Main storyboard

The view controller on the left is the root navigation controller of the app. Then you have:

  1. MasterViewController: This contains the table view that you’ll use to display and filter the candies you’re interested in.
  2. DetailViewController: This displays the details of the selected candy along with its image.

Build and run the app and you’ll see an empty list:

Empty table view

Back in Xcode, the file Candy.swift contains a struct to store the information about each piece of candy you’ll display. This struct has two properties:

  • name: This property has type String and is fairly self-explanatory.
  • category: This is an enum of type Candy.Category, which represents the category each candy belongs to. It also conforms to RawRepresentable so that you can convert it to and from an associated raw value of type String.

When the user searches for a type of candy in your app, you’ll search the name property using the user’s query string. The category will become important near the end of this tutorial, when you implement the scope bar.

Populating the Table View

Open MasterViewController.swift. You’ll manage all the different Candy for your users to search in candies. Speaking of which, it’s time to create some candy!

Note: In this tutorial, you only need to create a limited number of values to illustrate how the search bar works; in a production app, you might have thousands of these searchable objects. But whether an app has thousands of objects to search or just a few, the methods you use will remain the same. This is scalability at its finest!

To populate candies, add the following code to viewDidLoad() after the call to super.viewDidLoad():

candies = Candy.candies()

Build and run. Since the sample project has already implemented the table view’s data source methods, you’ll see that you now have a working table view:

Populated table view

Selecting a row in the table will also display a detail view of the corresponding candy:

Candy detail

So much candy, so little time to find what you want! You need a UISearchBar.

Introducing UISearchController

If you look at UISearchController‘s documentation, you’ll discover it’s pretty lazy. It doesn’t do any of the work of searching at all. The class simply provides the standard interface that users have come to expect from their iOS apps.

UISearchController communicates with a delegate protocol to let the rest of your app know what the user is doing. You have to write all of the actual functionality for string matching yourself.

Although this may seem scary at first, writing custom search functions gives you tight control over how your specific app returns results. Your users will appreciate searches that are intelligent and fast.

If you’ve worked with searching table views in iOS in the past, you may be familiar with UISearchDisplayController. Since iOS 8, Apple has deprecated this class in favor of UISearchController, which simplifies the entire search process.

In MasterViewController.swift, add a new property under candies‘ declaration:

let searchController = UISearchController(searchResultsController: nil)

By initializing UISearchController with a nil value for searchResultsController, you’re telling the search controller that you want to use the same view you’re searching to display the results. If you specify a different view controller here, the search controller will display the results in that view controller instead.

In order for MasterViewController to respond to the search bar, it must implement UISearchResultsUpdating. This protocol defines methods to update search results based on information the user enters into the search bar.

Still in MasterViewController.swift, add the following class extension outside of the main MasterViewController:

extension MasterViewController: UISearchResultsUpdating {
  func updateSearchResults(for searchController: UISearchController) {
    // TODO
  }
}

updateSearchResults(for:) is the one and only method that your class must implement to conform to the UISearchResultsUpdating protocol. You’ll fill in the details shortly.

Setting Up searchController‘s Parameters

Next, you need to set up a few parameters for your searchController. Still in MasterViewController.swift, add the following to viewDidLoad(), just after the assignment to candies:

// 1
searchController.searchResultsUpdater = self
// 2
searchController.obscuresBackgroundDuringPresentation = false
// 3
searchController.searchBar.placeholder = "Search Candies"
// 4
navigationItem.searchController = searchController
// 5
definesPresentationContext = true

Here’s a breakdown of what you’ve just added:

  1. searchResultsUpdater is a property on UISearchController that conforms to the new protocol, UISearchResultsUpdating. With this protocol, UISearchResultsUpdating will inform your class of any text changes within the UISearchBar.
  2. By default, UISearchController obscures the view controller containing the information you’re searching. This is useful if you’re using another view controller for your searchResultsController. In this instance, you’ve set the current view to show the results, so you don’t want to obscure your view.
  3. Here, you set the placeholder to something that’s specific to this app.
  4. New for iOS 11, you add the searchBar to the navigationItem. This is necessary because Interface Builder is not yet compatible with UISearchController.
  5. Finally, by setting definesPresentationContext on your view controller to true, you ensure that the search bar doesn’t remain on the screen if the user navigates to another view controller while the UISearchController is active.