30

I have an app with a UISearchController. This element of the UI is completely set up in code like this:

searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.searchBar.delegate = self
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.searchBarStyle = UISearchBarStyle.Minimal

searchController.searchBar.frame = CGRectMake(searchController.searchBar.frame.origin.x, searchController.searchBar.frame.origin.y, searchController.searchBar.frame.size.width, 44.0)

I am then adding it to my tableView's tableHeaderView

tableView.tableHeaderView = searchController.searchBar

Everything seems to be working fine, but when it's active and I select an item in my tableView, my app segues to another view controller with the search controller persisting in the view. I'm unsure as to how this is possible since the search controller should be a subview of the table view in another view controller. How can I prevent this from happening?

screenshot

Kilian
  • 2,122
  • 2
  • 24
  • 42
  • Would it be too hacky to just 'nil' it out in `prepareForSegue`? – Tim Quinn Apr 06 '15 at 21:54
  • The best part about this is that `tableView.tableHeaderView = nil` has no effect whatsoever when I call it in `prepareForSegue`. Or do you mean to nil out the entire `searchController`? I'm not sure what the best way to handle all of this would be in that case. – Kilian Apr 06 '15 at 21:59
  • 1
    try setting `searchController.active` to `false` in `prepareForSegue`. – Praveen Gowda I V Apr 08 '15 at 03:37
  • That seems to work, thanks! Mind throwing it into an answer? :) – Kilian Apr 09 '15 at 22:47

2 Answers2

60

You can hide the searchController manually by setting the active property to false in prepareForSegue. Add the below code in prepareForSegue()

searchController.active = false

Alternatively, you should add the following line in viewDidLoad() to get the default behaviour

definesPresentationContext = true

From the documentation for definesPresentationContext

A Boolean value that indicates whether this view controller's view is covered when the view controller or one of its descendants presents a view controller.

Discussion

When a view controller is presented, iOS starts with the presenting view controller and asks it if it wants to provide the presentation context. If the presenting view controller does not provide a context, then iOS asks the presenting view controller's parent view controller. iOS searches up through the view controller hierarchy until a view controller provides a presentation context. If no view controller offers to provide a context, the window's root view controller provides the presentation context.

If a view controller returns true, then it provides a presentation context. The portion of the window covered by the view controller's view determines the size of the presented view controller's view. The default value for this property is false.

Important note (from @paulvs in the comments)

Little gotcha. Set definesPresentationContext on the view controller, not the search controller, I think this is worth emphasising.

DeepBlue
  • 591
  • 9
  • 18
Praveen Gowda I V
  • 9,569
  • 4
  • 41
  • 49
  • Thank you! Especially about the bit about the presentation context! – Kilian Apr 14 '15 at 18:41
  • 2
    4 hours of searching and trying different options, and couldn't find working solution for that ! tried to **searchBar.hidden = true** but it was making so much damage everywhere. thanks again ! – Slav Apr 15 '15 at 03:46
  • 3
    definesPresentationContext is completely the right answer. If you use any other option like dismiss or active to false, it cancels your original search, whereas definesPresentationContext takes you back to exactly how you'd expect things to be. Many thanks. – Darren May 08 '15 at 23:22
  • 7
    Little gotcha. Set definesPresentationContext on the view controller, not the search controller, I think this is worth emphasising. – paulvs Jan 06 '16 at 15:49
  • Setting `active` to false was the key for me -- presenting a view controller on top of the search controller was crashing the app. Thanks! – wcochran Mar 10 '16 at 02:22
  • If you find the keyboard stays around for a little too long, you can add a searchController.searchBar.resignFirstResponder() at the top of prepareForSegue also. – Jonathan Berger Apr 12 '16 at 22:45
  • In my case (iOS 10.3), setting `searchController.isActive = false` inside `prepare(for:sender:)` prevents me from segueing from any table view cell to its view controller as it should be even though `tableView(_:didSelectRowAt:)` did fire every time a table view row is selected. So, the solution is to move `searchController.isActive = false` inside `viewWillDisappear(_:)`. – yohannes Apr 08 '17 at 10:02
4

If you manage your own transitions and use popToViewController to leave the view, provide the context on the searchController instead of the view

searchController.definesPresentationContext = true

or you will get an error

popToViewController:transition: called on <UINavigationController 0x7f984204f800> while an existing transition or presentation is occurring; the navigation stack will not be updated
Mat
  • 41
  • 1