App development

UISearchController Tutorial: Getting Began [FREE]

Replace word: Lorenzo Boaro up to date this tutorial to Xcode 11, Swift 5 and iOS 13. Tom Elliott wrote the unique.

Scrolling by means of large lists of things is usually a sluggish and irritating course of for customers. When coping with massive datasets, it’s vitally essential to let the person seek for particular gadgets. UIKit consists of UISearchBar, which seamlessly integrates with UINavigationItem by way of a UISearchController and permits for fast, responsive filtering of data.

On this tutorial, you’ll construct a searchable Sweet app based mostly on a regular desk view. You’ll add desk view search functionality, dynamic filtering and an elective scope bar, all whereas making the most of UISearchController. In the long run, you’ll know the way to make your apps rather more user-friendly and the way to fulfill your customers’ pressing calls for.

Prepared for some sugar-coated search outcomes? Learn on.

Getting Began

Begin by downloading the starter mission utilizing the Obtain Supplies button on the prime or backside of this tutorial. As soon as it’s downloaded, open CandySearch.xcodeproj in Xcode.

To maintain you centered, the starter mission has the whole lot unrelated to looking and filtering already arrange for you.

Open Primary.storyboard and take a look at the view controllers contained inside:

The view controller on the left is the foundation navigation controller of the app. Then you’ve got:

MasterViewController: This incorporates the desk view that you just’ll use to show and filter the candies you’re excited by.

DetailViewController: This shows the small print of the chosen sweet together with its picture.

Construct and run the app and also you’ll see an empty listing:

Empty table view

Again in Xcode, the file Sweet.swift incorporates a struct to retailer the details about every bit of sweet you’ll show. This struct has two properties:

title: This property has sort String and is pretty self-explanatory.

class: That is an enum of sort Sweet.Class, which represents the class every sweet belongs to. It additionally conforms to RawRepresentable with the intention to convert it to and from an related uncooked worth of sort String.

When the person searches for a sort of sweet in your app, you’ll search the title property utilizing the person’s question string. The class will change into essential close to the top of this tutorial, while you implement the scope bar.

Populating the Desk View

Open MasterViewController.swift. You’ll handle all of the completely different Sweet in your customers to look in candies. Talking of which, it’s time to create some sweet!

Notice: On this tutorial, you solely have to create a restricted variety of values as an instance how the search bar works; in a manufacturing app, you may need 1000’s of those searchable objects. However whether or not an app has 1000’s of objects to look or just some, the strategies you utilize will stay the identical. That is scalability at its best!

To populate candies, add the next code to viewDidLoad() after the decision to tremendous.viewDidLoad():

candies = Sweet.candies()

Construct and run. Because the pattern mission has already applied the desk view’s knowledge supply strategies, you’ll see that you just now have a working desk view:

Populated table view

Deciding on a row within the desk may also show a element view of the corresponding sweet:

Candy detail

A lot sweet, so little time to seek out what you need! You want a UISearchBar.

Introducing UISearchController

If you happen to take a look at UISearchController‘s documentation, you’ll uncover it’s fairly lazy. It doesn’t do any of the work of looking in any respect. The category merely offers the usual interface that customers have come to count on from their iOS apps.

UISearchController communicates with a delegate protocol to let the remainder of your app know what the person is doing. It’s a must to write all the precise performance for string matching your self.

Though this will likely appear scary at first, writing customized search features offers you tight management over how your particular app returns outcomes. Your customers will recognize searches which are clever and quick.

If you happen to’ve labored with looking desk views in iOS prior to now, you could be aware of UISearchDisplayController. Since iOS eight, Apple has deprecated this class in favor of UISearchController, which simplifies the complete search course of.

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

let searchController = UISearchController(searchResultsController: nil)

By initializing UISearchController with a 0 worth for searchResultsController, you’re telling the search controller that you just wish to use the identical view you’re looking to show the outcomes. If you happen to specify a distinct view controller right here, the search controller will show the leads to that view controller as a substitute.

To ensure that MasterViewController to reply to the search bar, it should implement UISearchResultsUpdating. This protocol defines strategies to replace search outcomes based mostly on data the person enters into the search bar.

Nonetheless in MasterViewController.swift, add the next class extension outdoors of the primary MasterViewController:

extension MasterViewController: UISearchResultsUpdating
func updateSearchResults(for searchController: UISearchController)

updateSearchResults(for:) is the one and solely methodology that your class should implement to adapt to the UISearchResultsUpdating protocol. You’ll fill within the particulars shortly.

Setting Up searchController‘s Parameters

Subsequent, you have to arrange a number of parameters in your searchController. Nonetheless in MasterViewController.swift, add the next to viewDidLoad(), simply after the task to candies:

// 1
searchController.searchResultsUpdater = self
// 2
searchController.obscuresBackgroundDuringPresentation = false
// three
searchController.searchBar.placeholder = “Search Candies”
// four
navigationItem.searchController = searchController
// 5
definesPresentationContext = true

Right here’s a breakdown of what you’ve simply added:

searchResultsUpdater is a property on UISearchController that conforms to the brand new protocol, UISearchResultsUpdating. With this protocol, UISearchResultsUpdating will inform your class of any textual content adjustments inside the UISearchBar.
By default, UISearchController obscures the view controller containing the knowledge you’re looking. That is helpful should you’re utilizing one other view controller in your searchResultsController. On this occasion, you’ve set the present view to indicate the outcomes, so that you don’t wish to obscure your view.
Right here, you set the placeholder to one thing that’s particular to this app.
New for iOS 11, you add the searchBar to the navigationItem. That is needed as a result of Interface Builder isn’t but appropriate with UISearchController.
Lastly, by setting definesPresentationContext in your view controller to true, you make sure that the search bar doesn’t stay on the display screen if the person navigates to a different view controller whereas the UISearchController is lively.

Filtering With UISearchResultsUpdating

After you arrange the search controller, you’ll have to do some coding to get it working. First, add the next property close to the highest of MasterViewController:

var filteredCandies: [Candy] = []

This property will maintain the candies that the person searches for.

Subsequent, add the next computed property to the primary MasterViewController:

var isSearchBarEmpty: Bool
return searchController.searchBar.textual content?.isEmpty ?? true

isSearchBarEmpty returns true if the textual content typed within the search bar is empty; in any other case, it returns false.

Nonetheless inside MasterViewController.swift, add the next methodology on the finish of MasterViewController:

func filterContentForSearchText(_ searchText: String,
class: Sweet.Class? = nil)
filteredCandies = candies.filter (sweet: Sweet) -> Bool in
return sweet.title.lowercased().incorporates(searchText.lowercased())


filterContentForSearchText(_:class:) filters candies based mostly on searchText and places the leads to filteredCandies, which you’ve simply added. Don’t fear in regards to the class parameter for now; you’ll use that in a later part of this tutorial.

filter(_:) takes a closure of sort (sweet: Sweet) -> Bool. It then loops over all the weather of the array and calls the closure, passing within the present ingredient, for each one of many parts.

You need to use this to find out whether or not a sweet needs to be a part of the search outcomes that the person receives. To take action, you have to return true if you wish to embody the present sweet within the filtered array or false in any other case.

To find out this, you utilize incorporates(_:) to see if the title of the sweet incorporates searchText. However earlier than doing the comparability, you exchange each strings to their lowercase equivalents utilizing lowercased().

Notice: More often than not, customers don’t hassle with the case of letters when performing a search, so by solely evaluating the lowercase model of what they sort with the lowercase model of the title of every sweet, you possibly can simply return a case-insensitive match. Now, you possibly can sort “Chocolate” or “chocolate” and both will return an identical sweet. How helpful is that?! :]

Bear in mind UISearchResultsUpdating? You left it unimplemented. Properly, you’ve simply written a technique that you just wish to name while you replace the search outcomes. Voilà!

Exchange the TODO in updateSearchResults(for:) with the next code:

let searchBar = searchController.searchBar
filterContentForSearchText(searchBar.textual content!)

Now, every time the person provides or removes textual content within the search bar, the UISearchController will inform the MasterViewController class of the change by way of a name to updateSearchResults(for:), which in flip calls filterContentForSearchText(_:class:).

Construct and run and also you’ll discover that there’s now a search bar above the desk. It’s possible you’ll have to scroll right down to see it.

Scrolling table view

Nonetheless, while you enter search textual content, you continue to don’t see any filtered outcomes. What offers?

That is merely since you haven’t written the code to let the desk view know when to make use of the filtered outcomes but.

Updating the Desk View

In the primary MasterViewController class of MasterViewController.swift, add a computed property to find out in case you are at present filtering outcomes or not:

var isFiltering: Bool

Subsequent, exchange tableView(_:numberOfRowsInSection:) with the next:

func tableView(_ tableView: UITableView,
numberOfRowsInSection part: Int) -> Int

Not a lot has modified right here. You merely test whether or not the person is looking or not, then use both the filtered or the conventional candies as the info supply for the desk.

Subsequent, exchange tableView(_:cellForRowAt:) with the next:

func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: “Cell”, for: indexPath)
let sweet: Sweet
if isFiltering
sweet = filteredCandies[indexPath.row]
cell.textLabel?.textual content = sweet.title
cell.detailTextLabel?.textual content = sweet.class.rawValue
return cell

Each strategies now use isFiltering, which refers back to the isActive property of searchController to find out which array to show.

When the person faucets the search subject of the search bar, isActive is mechanically set to true. If the search controller is lively and the person has typed one thing into the search subject, the returned knowledge comes from filteredCandies. In any other case, the info comes from the total listing of things.

Keep in mind that the search controller mechanically handles exhibiting and hiding the outcomes desk, so all of your code has to do is present the right knowledge (filtered or non-filtered) relying on the state of the controller and whether or not the person has looked for something.

Construct and run the app. You now have a functioning Search Bar that filters the rows of the primary desk. Huzzah!

Filtering with search bar

Play with the app for a bit to see how one can seek for numerous candies.

However wait, there’s nonetheless yet another drawback. When you choose a row from the search outcomes listing, you could discover the element view is from the unsuitable sweet! Time to repair that.

Sending Knowledge to a Element View

When sending data to a element view controller, you have to make sure the view controller is aware of which context the person is working with: The complete desk listing or the search outcomes. Right here’s the way you deal with that.

Nonetheless in MasterViewController.swift, in put together(for:sender:), discover the next code:

let sweet = candies[indexPath.row]

And exchange it with the next:

let sweet: Sweet
if isFiltering
sweet = filteredCandies[indexPath.row]

Right here, you carry out the identical isFiltering test as earlier than, however now you’re offering the right sweet object when segueing to the element view controller.

Construct and run the code at this level and see how the app now navigates appropriately to the element view from both the primary desk or the search desk with ease.

Making a Scope Bar to Filter Outcomes

To present your customers one other option to filter their outcomes, add a scope bar at the side of your search bar to filter gadgets by class. The classes you’ll filter by are those you assigned to the sweet object while you created candies: Chocolate, Exhausting and Different.

First, it’s a must to create a scope bar in MasterViewController. The scope bar is a segmented management that narrows a search by solely wanting in sure scopes. The scope is no matter you outline it to be. On this case, it’s a sweet’s class, however scopes is also varieties, ranges or one thing fully completely different.

Utilizing the scope bar is as simple as implementing one extra delegate methodology.

In MasterViewController.swift, you’ll add one other extension that conforms to UISearchBarDelegate. So after UISearchResultsUpdating, which you added earlier, add the next:

extension MasterViewController: UISearchBarDelegate
func searchBar(_ searchBar: UISearchBar,
selectedScopeButtonIndexDidChange selectedScope: Int)

You name this delegate methodology when the person switches the scope within the scope bar. When that occurs, you wish to redo the filtering. Because of RawRepresentable conformance, you create a brand new class occasion that retrieves the required uncooked worth from the chosen scope button title. So that you name filterContentForSearchText(_:class:) with the brand new class.

Now, modify filterContentForSearchText(_:class:) to take the provided class into consideration:

func filterContentForSearchText(_ searchText: String,
class: Sweet.Class? = nil)
filteredCandies = candies.filter sweet.class == class

if isSearchBarEmpty
return doesCategoryMatch
return doesCategoryMatch && sweet.title.lowercased()


This now checks to see if the class of the sweet matches the class that the scope bar passes, or whether or not the scope is ready to .all. You then test to see if there may be textual content within the search bar and filter the sweet appropriately. Now, exchange isFiltering with the next:

var isFiltering: Bool searchBarScopeIsFiltering)

Right here, you replace isFiltering to return true when the person selects the scope bar.

You’re virtually completed, however the scope filtering mechanism doesn’t fairly work but. You’ll want to switch updateSearchResults(for:) within the top quality extension you created to ship the present class:

func updateSearchResults(for searchController: UISearchController)

The one drawback left is that the person doesn’t really see a scope bar but! Inside MasterViewController.swift in viewDidLoad(), add the next code simply after the search controller setup:

searchController.searchBar.scopeButtonTitles = Sweet.Class.allCases
.map $zero.rawValue
searchController.searchBar.delegate = self

Since Sweet.Class conforms to CaseIterable, the compiler can mechanically synthesize allCases for any RawRepresentable enumeration, including the titles that match the classes you assigned to your sweet objects.

Now, while you sort, the chosen scope button will seem at the side of the search textual content.

Testing the Scope Bar

Construct and run. Attempt coming into some search textual content and altering the scope.

Scope application

Kind in “caramel” with the scope set to “All”. It reveals up within the listing, however while you change the scope to Chocolate, “caramel” disappears as a result of it’s not a chocolate-type sweet. Hurrah!

There’s nonetheless one small drawback with the app. You haven’t added a outcomes indicator to inform the person what number of outcomes they need to count on to see. That is notably essential when no outcomes are returned in any respect, because it’s tough for the person to tell apart between no outcomes returned and a delay in receiving the reply attributable to a sluggish community connection.

Including a Outcomes Indicator

To repair this, you’re going so as to add a footer to your view. The person will see this footer after they filter the listing of candies, and it’ll inform them what number of candies are within the filtered array.

Begin by opening SearchFooter.swift. Right here, you’ve got a easy UIView which incorporates a label in addition to a public API that may obtain the variety of outcomes returned.

Head again to MasterViewController.swift. searchFooter is an IBOutlet for the search footer that the starter mission already arrange for you. You will discover it within the grasp scene in Primary.storyboard, on the backside of the display screen.

Inside MasterViewController.swift, add the next to viewDidLoad(), after the spot the place you arrange the scope bar:

let notificationCenter = NotificationCenter.default
forName: UIResponder.keyboardWillChangeFrameNotification,
object: nil, queue: .essential) (notification) in
self.handleKeyboard(notification: notification)

forName: UIResponder.keyboardWillHideNotification,
object: nil, queue: .essential) (notification) in
self.handleKeyboard(notification: notification)

These two observers let you management the outcomes indicator, which can transfer up or down based mostly on the visibility of the system keyboard.

Subsequent, add this methodology to MasterViewController:

func handleKeyboard(notification: Notification)

Right here’s what’s taking place with the code you simply added:

You first test if the notification is has something to do with hiding the keyboard. If not, you progress the search footer down and bail out.
If the notification identifies the ending body rectangle of the keyboard, you progress the search footer simply above the keyboard itself.

In each instances, you handle the gap between the search footer and the underside of the display screen by means of a constraint represented by an IBOutlet known as searchFooterBottomConstraint.

Lastly, you have to replace the variety of leads to the search footer when the search enter adjustments. So exchange tableView(_:numberOfRowsInSection:) with the next:

func tableView(_ tableView: UITableView,
numberOfRowsInSection part: Int) -> Int

All you’ve executed right here is so as to add in calls to the searchFooter.

Construct and run, carry out a number of searches and watch because the footer updates.

Show filter

The place to Go From Right here?

Congratulations! You now have a working app that means that you can search immediately from the primary desk view.

You possibly can obtain the ultimate mission utilizing the Obtain Supplies button on the prime or backside of this tutorial.

All types of apps use desk views, and providing a search choice is a pleasant contact that improves usability. With UISearchBar and the UISearchController, iOS offers a lot of the performance out of the field, so there’s no excuse to not use it. The power to look a big desk view is one thing that immediately’s customers count on; with out it, they received’t be completely satisfied campers.

Within the meantime, when you’ve got any questions or feedback, please be a part of the discussion board dialogue beneath!

wordpress autoblog
amazon autoblog
affiliate autoblog
wordpress web site
web site improvement

Related posts

New! Study superior expertise for growing Android apps in Kotlin


Write an AWS Lambda Perform with Kotlin and Micronaut [FREE]


Android Intents Tutorial with Kotlin [FREE]


Leave a Comment