Search code examples
swiftuisearchcontroller

UISeachController Delegate methods not called, searchbar can't become first responder


I'm having some difficulty getting the searchbar in my searchcontroller to become firstResponder. I've noticed the delegate methods are not being called, but the searchbar works as intended when I'm typing to filter a list of users.

Definition of searchcontroller:

lazy var searchController: UISearchController = {
    let searchController = UISearchController(searchResultsController: nil)
    searchController.searchResultsUpdater = self
    searchController.obscuresBackgroundDuringPresentation = false
    searchController.searchBar.placeholder = "Search"
    return searchController
}()

Setting it up:

private func setupSearchController() {
    self.navigationItem.searchController = searchController
    searchController.definesPresentationContext = true
    searchController.delegate = self
    searchController.isActive = true
    searchController.searchBar.delegate = self
    searchController.searchBar.becomeFirstResponder()
}

I tried this suggestion from another SO question but the delegate method isn't being called:

func didPresentSearchController(searchController: UISearchController) {
    UIView.animate(withDuration: 0.1, animations: { () -> Void in }) { (completed) -> Void in
        searchController.searchBar.becomeFirstResponder()
    }
}

Solution

  • The problem is you are trying to access UI element(searchbarcontroller) before UI is completely loaded. This can be done in 2 ways

    1. Use main queue to show keypad

      private func setupSearchController() {
           self.navigationItem.searchController = searchController
           searchController.definesPresentationContext = true
           searchController.delegate = self
           searchController.isActive = true
           searchController.searchBar.delegate = self
           DispatchQueue.main.async {
                 self.searchController.searchBar.becomeFirstResponder()
           } 
      }
      

    With this approach keypad will be only show at one time in viewDidLoad

    1. Show keypad in viewDidAppear

       override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            DispatchQueue.main.async {
                self.searchController.searchBar.becomeFirstResponder()
            }
       }
      

    With this approach keypad will be always shown whenever screen appears.