How to write Async Search Bar Controller | Fission Labs
iOS

How to write Async Search Bar Controller

How do you handle the search if you are searching among millions of records? What happens when a user enters some text to search and realised that he wanted to search something else or mistyped something? Ideally, when a user changes the text we should stop our search and begin a search with the new […]

Fission Labs • July 11, 2019

How do you handle the search if you are searching among millions of records?

What happens when a user enters some text to search and realised that he wanted to search something else or mistyped something?

Ideally, when a user changes the text we should stop our search and begin a search with the new text entered by a user.

How should we write such a code in swift to make sure we cancel the search before starting a new search?

OperationQueue is a good way to handle these kinds of situations. So, let’s get our hands dirty to write a piece of code for it.

We need a delegate which provides a set of APIs to use search functionality as below:

protocol SearchControllerDelegate: class {
var searchQueue:OperationQueue {get set}
var searchResult:[FlickrPhoto] {get set}
func searchDisplayController(controller:SearchViewController, searchText:String)
func cancelSearch()
}

We just wrote a SearchControllerDelegate protocol which has properties and methods as:

Properties:

  • searchQueue to perform Async search task.
  • searchResult stores results returned from the search.

Methods:

  • searchDisplayController(controller:SearchViewController, searchText:String) to start a search with the searchText
  • cancelSearch() to cancel the search

Here, how do we use delegate protocol in our ViewController:

extension SearchViewController {
func searchDisplayController(controller:SearchViewController, searchText:String) {
guard !searchText.isEmpty else {
self.searchResult.removeAll()
return
}
self.searchQueue.cancelAllOperations()
self.searchQueue.addOperation { [weak self] in
DispatchQueue.main.async(execute: { () -> Void in
UIApplication.shared.isNetworkActivityIndicatorVisible = true
})
FlickrDataManager().fetchPhotosForSearchText(searchText: searchText, onCompletion: { (error: NSError?, flickrPhotos: [FlickrPhoto]?) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
UIApplication.shared.isNetworkActivityIndicatorVisible = false
})
if error == nil {
self?.searchResult = flickrPhotos!
} else {
self?.searchResult = []
if (error!.code == FlickrDataManager.Errors.invalidAccessErrorStatusCode) {
DispatchQueue.main.async(execute: { () -> Void in
self?.showErrorAlert()
})
}
}
DispatchQueue.main.async(execute: { () -> Void in
self?.title = searchText
self?.tableView.reloadData()
})
})
}
}
func cancelSearch() {
self.searchQueue.cancelAllOperations()
self.searchResult.removeAll()
self.title = “”
}
}

How to connect SearchControllerDelegate to UI:

class SearchViewController: UIViewController, SearchControllerDelegate, UISearchBarDelegate {
var searchQueue: OperationQueue = OperationQueue()
var searchResult: [FlickrPhoto] = []
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var tableView: UITableView!
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
self.cancelSearch()
        self.searchDisplayController(controller: self, searchText:  searchBar.text!)
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
self.cancelSearch()
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
self.searchDisplayController(controller: self, searchText: searchBar.text!)
}

A simple example of the Async search can be found here.

Originally published at https://medium.com/@coolanil.saini/how-to-write-async-searchbarcontroller-6e8e00082dbc