iOS App Development iOS Swift Tutorial iOS8

Swift iOS Tutorial: UISearchBar and UISearchBarDelegate

One of the most important feature in an iOS application would be searching functionality, today we will be learning how to add search to our tableview application in Swift using UISearchBar and UISearchBarDelegate

UISearchBar

The UISearchBar class implements a text field control for text-based searches. The control provides a text field for entering text, a search button, a bookmark button, and a cancel button. The UISearchBar object does not actually perform any searches. You use a delegate, an object conforming to the UISearchBarDelegate protocol, to implement the actions when text is entered and buttons are clicked. You can hide and show the cancel button by setting `showsCancelButton` to false or true.

UISearchBarDelegate

The UISearchBarDelegate protocol defines the optional methods you implement to make a UISearchBar control functional. A UISearchBar object provides the user interface for a search field on a bar, but it’s the application’s responsibility to implement the actions when buttons are tapped. At a minimum, the delegate needs to perform the actual search when text is entered in the text field.

The main function which we will be implementing are

optional func searchBar(_ searchBar: UISearchBar,
          textDidChange searchText: String)

We will maintain a boolean variable `searchActive` to decide if the search is in progress.

Steps to implement search

  • Create a single view application.

images

  • Disable Size classes for now.

images

  • Select the tableview and set the autolayout constraints to 0.

images

If you are interested in learning iOS Development I suggest you take a look at Build an app every month

  • To the existing controller add the tableview and a tableview cell on top of the tableview.Select the tableview Cell go to the attribute inspect and provide the identifier as `Cell`

images

  •  Select the view controller. Select Editor > Embed In > Navigation Controller.

images

  • Create IBOutlet from tableview and the searchbar. `CTRL+DRAG` from tableview and searchbar to the viewcontroller.swift

images

  • Lets conform to the UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate. Also in viewDidLoad
    set the datasource and delegate to self.
/* Setup delegates */
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
  • Search functionality is very simple. We just filter the `data` array and if it matches the text we create
    a new array called `filtered` which holds the text which matches the text in the searchbar.
  • Depending on the `searchActive` we return either the `filtered` or the actual `data` in the `numberOfRowsInSection`
    and `cellForRowAtIndexPath`

Below is the complete code required to implement the functionality.

//
//  ViewController.swift
//  SwiftSearch
//
//  Created by Shrikar Archak on 2/16/15.
//  Copyright (c) 2015 Shrikar Archak. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate{

    @IBOutlet weak var searchBar: UISearchBar!
    @IBOutlet weak var tableView: UITableView!

    var searchActive : Bool = false
    var data = ["San Francisco","New York","San Jose","Chicago","Los Angeles","Austin","Seattle"]
    var filtered:[String] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        /* Setup delegates */
        tableView.delegate = self
        tableView.dataSource = self
        searchBar.delegate = self

    }

    func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
        searchActive = true;
    }

    func searchBarTextDidEndEditing(searchBar: UISearchBar) {
        searchActive = false;
    }

    func searchBarCancelButtonClicked(searchBar: UISearchBar) {
        searchActive = false;
    }

    func searchBarSearchButtonClicked(searchBar: UISearchBar) {
        searchActive = false;
    }

    func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {

        filtered = data.filter({ (text) -> Bool in
            let tmp: NSString = text
            let range = tmp.rangeOfString(searchText, options: NSStringCompareOptions.CaseInsensitiveSearch)
            return range.location != NSNotFound
        })
        if(filtered.count == 0){
            searchActive = false;
        } else {
            searchActive = true;
        }
        self.tableView.reloadData()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if(searchActive) {
            return filtered.count
        }
        return data.count;
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell;
        if(searchActive){
            cell.textLabel?.text = filtered[indexPath.row]
        } else {
            cell.textLabel?.text = data[indexPath.row];
        }

        return cell;
    }
}

Initial Load

images

On text in the textbar

images

If you want to implement search using parse take a look at this tutorial Parse search in iOS8 with Swift
Please let me know if you have any feedback or questions.

Requested tutorials from readers

Search

To get this functionality we need to add these 3 function. First we need to change the style of the tableview from plain to grouped. Next we need to tell the height of the tableview header which in our case is 44.
Also we need to creat a segmentedControl and return the control for TableView viewForHeaderInSection. In our case we want to change the data when segmented view Control value is changed. So we will addTarget to the segmentedControl which will be called when the value is changed.

    /* Create these variable to hold different data *.
    var data = ["San Francisco","New York","San Jose","Chicago","Los Angeles","Austin","Seattle"]
    var data0 = ["San Francisco","New York","San Jose","Chicago","Los Angeles","Austin","Seattle"]
    var data1 = ["Data1","Data11","Data111"]
    var data2 = ["Data2","Data22","Data222"]

    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let control = UISegmentedControl(items: ["Seg1","Seg2","Seg3"])
        control.addTarget(self, action: "valueChanged:", forControlEvents: UIControlEvents.ValueChanged)
        if(section == 0){
            return control;
        }
        return nil;
    }
    
    func valueChanged(segmentedControl: UISegmentedControl) {
        println("Coming in : \(segmentedControl.selectedSegmentIndex)")
        if(segmentedControl.selectedSegmentIndex == 0){
            self.data = self.data0
        } else if(segmentedControl.selectedSegmentIndex == 1){
            self.data = self.data1
        } else if(segmentedControl.selectedSegmentIndex == 2){
            self.data = self.data2
        } else {
            self.data = data0
        }
        self.tableView.reloadData()
    }

    func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 44.0
    }

About the author

Shrikar

Backend/Infrastructure Engineer by Day. iOS Developer for the rest of the time.

  • fendy

    filtered = data.filter({ (text) -> Bool in

    text at above is variable?

    • http://shrikar.com shrikar

      yes that is what will be passed for your block.

  • Ian Miller

    I am trying to implement this on a core data app. How do I change the “data” variable for your array to point this to core data instead? Also, does your line starting “filtered” etc compile on the latest version of Swift and Xcode – I am getting some errors. Can you comment?

  • Phu Nguyen

    Thank you for your tutorial :)
    As I implemented, we should not set searchActive = true in searchBarTextDidBeginEditing which causes crash if I tap on search bar (have not typed any letter) and scroll the tableview.

  • iphone development

    Hello Shrikar,

    Thanks a lot for very nice tutorial.

    I had a question, if there is lot of data in the tableview it is very hard to come back to the tableheaderview. So I was wondering if i added a barbuttonitem (search button). On clicking the search button how can we invoke the UIsearchbar???? Could you please help me ?

    Thanks

  • mahamudul11

    How to stop initial search loading…

    • James Hartley

      Yeah, has anyone found an answer to this? It would look so much cleaner if the data is not automatically shown like this.

      • Bishek

        hide the tableview while search is not active and show it when search is active…

  • Anuraag D Jain

    I’m displaying text with a image. By implementing the above code, I can filter and get the exact text, but the image doesn’t change. How should I implement the code so that the text and it’s appropriate image is shown?

  • Sidney de Koning

    Hi,
    There is actually a property on the the UISearchController called ‘active’. And since the UISearchBar is embedded within a UISearchController, you get this for free when conforming to the UISearchControllerDelegate. So there is no need to implement this yourself. Also you get has a nice protocol called ‘UISearchResultsUpdating’ which allows even more control.

    Best,
    Sidney

  • Wesley Mota

    Great tutorial. I’m new in Swift. So I need to know how filter data from CloudKit. Here you used array of string. On my case I use CKArray and I tried to convert to String but no success. Does anyone know how to get this?

    var arrNotes: Array = []

  • Alanna Wynn

    I am having a problem with a tableview. I have a navigation bar with a back button and a search bar. Every time you use the search bar, the navigation bar is covered and you are unable to return to the previous screen. Any suggestions?

    • http://shrikar.com shrikar

      Looks like some issue with the autolayout if search bar is covering navigation bar. If navbar is covering searchbar then you can try setting edgesForExtendedLayout = UIRectEdgeNone

  • Robin

    hello everybody ! someone know how to use a UISearchBar, UITableView with external data from JSON file ?
    thanks for your help

  • Asmita

    HI Shrikar , i want implement same but using objective c , can you please tell how i implement it, thanks

  • Sweatha Amarnath

    It’s one of the best tutorial ‘ve seen.Simple and Working too.. I want the same to be implemented for NSMutableArray since my tableview is dynamic. Can you pls help me out for this? i converted the data and filtered data to String as in your case but then my app gets crashed while entering into cellForRowAtIndexPath function! I tried best to sort out but couldn’t..I’m new to swift so pls bear with me :)

    Thanks in advance..

  • Spark

    I have a little problem with the UITable, when I search this change my tableview with a custom UITableview

    My UITableViewCell has height: 136 but I filter some this change that value (It’s another tableview)

  • Sascha

    Nice tut, thx!

  • Gopi Nath

    Hello Shrikar,

    Thanks a lot for very nice tutorial.

    I had a question,i trying to search the data from the SQLite when i am searching the data in search it doesn’t display any results, can you please tell the solution for this.

    thanks for your help

  • Shrey

    I have two questions:

    1. The code for the simple UISearchBar works. It definitely searches all items in the Table. But when I tap the Search Bar don’t type in anything and then press a cell then the App just crashes. What code to stop this from happening?

    2. When I create a class Detail for the the data in the tables- var detail : [Detail]? -I can’t make the error in the filtered function go away- cannot assign value of type [Details] to type [String]. Any help with this? thanks!

  • Nishat

    I have the following problem.When I try to move to another view controller on click of a button,if the search controller is active it overrides the button click event and search controller is deactivated.We have to press the button once more to move to another view controller.
    ]

  • Anirudha Mahale

    How do I show the results in Virtual ViewController? I know there is something I have to do with UISearchDisplayDelegate protocol’s method but exactly what?

  • Kasper Wintiz

    You are aware you forgot to add the Search Bar to the view controller. I feel like this was the most vital step.

  • Dev Abhi

    Did you copy it from somewhere? I am sure you did. many important steps are missing and no source code for download. Don’t bluff the readers and waste there time.

  • andrew

    thanks for that!

  • Vinay Kumar

    How to search section, row titles when expandable tableview?

/* ]]> */