I'm having this bizarre issue and I have been trying to tackle it down for the past few hours with no luck.
I have a UISearchController
that shows up when the user taps a UIBarButtonItem
in a navigation bar. The button was created with IB and then wired to its IBAction, which is this one:
@IBAction func searchButtonTapped(sender: UIBarButtonItem) {
searchController.active = true
self.presentViewController(searchController, animated: true, completion: nil)
}
It works perfectly. The view controller shows up and the user can type stuff.
Additionally to simply tapping the search bar button item, I want to give users more power by using that button. Namely, I want them to be able to long-press it and force-touch it to do different actions within my app.
After hacking and searching on SO for a while (and because UIBarButtonItem is not a view on itself...), I found a way to add some gesture recognizers the search bar button item. I added this in my viewDidLoad
method.
if let searchBarButtonView = self.searchBarButtonItem.valueForKey("view") as? UIView where searchBarButtonView.respondsToSelector("addGestureRecognizer:") {
if Settings.searchCollectionMagnifierGlassIconLongPressAction != .None {
let longTapGr = UILongPressGestureRecognizer(target: self, action: "handleSearchBarButtonLongPressGesture:")
longTapGr.minimumPressDuration = CFTimeInterval(Settings.searchCollectionMagnifierGlassIconLongPressActionTime)
longTapGr.delegate = self
searchBarButtonView.addGestureRecognizer(longTapGr)
}
if Settings.searchCollectionMagnifierGlassIconForceTouchAction != .None {
let forceTouchGr = DFContinuousForceTouchGestureRecognizer()
forceTouchGr.forceTouchDelegate = self
forceTouchGr.triggeringForceTouchPressure = 2.0
searchBarButtonView.addGestureRecognizer(forceTouchGr)
}
}
You can ignore everything force-touch related for this question, as I am focusing on making long tap work first.
The gesture recognizers work fine. For the long tap gesture recognizer, this is the implementation for handleSearchBarButtonLongPressGesture:
:
func handleSearchBarButtonLongPressGesture(recognizer: UILongPressGestureRecognizer) {
self.performSearchCollectionMagnifierGlassAction(Settings.searchCollectionMagnifierGlassIconLongPressAction)
}
And this is the implementation for performSearchCollectionMagnifierGlassAction
:
func performSearchCollectionMagnifierGlassAction(action: Settings.SearchCollectionMagnifierGlassIconAction) {
let action = Settings.searchCollectionMagnifierGlassIconLongPressAction
if action == .ClearOldQueryAndSearch {
self.searchController.searchBar.text = ""
self.searchButtonTapped(self.searchBarButtonItem) // This is exactly as if the user tapped the search bar button item on his own... But it crashes when it gets called as a result of a gesture recognizer!
}
}
(I have removed other ifs here to make the code relevant. The other ifs only check for other actions and as such they don't get called).
Long-pressing my search bar button works fine. But the app crashes with:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modally an active controller
If I simply tap the search button, the app will not crash. I can show and hide the UISearchController
as many times as I wish that way. Like you can see, long pressing the search button will do exactly what normally tapping the button would do, except it clears the text field before showing it. I tried commenting out the line that empties the searchBar, but the crash still happens. Considering that almost the same exact code gets called when long tapping and simple-tapping the search button, I am inclined to think that this is crash may be, oddly, related to the gesture recognizer.
I have also tried dismissing the searchController even when it's not present before clearing the searchBar and presenting it again. No luck.
Finally, I have copied and pasted the code from searchButtonTapped
to performSearchCollectionMagnifierGlassAction
. No luck there, either.
Your searchButtonTapped
method is being called twice: in long tap gesture handler and directly when UIBarButtonItem's view emits touch up event.
Try to comment out your searchButtonTapped
call or set cancelsTouchesInView
property of longTapGr
to true
.