Edit: My apologies. I had bookmarked a number of UISplitViewCOntoller/UISearchBar posts. After posting this, I realized I posted on the wrong bookmark. This solution addresses a bug where the search controller does NOT display on the intended detail view controller when the split view is collapsed, but DOES erroneously display on the next segued view controller. This workaround is for THAT situation. I'm going to leave this post here, because it may help you, and for others struggling to find a solution for these problems, as I have been for several weeks.
I'm afraid there is no 100% equitable solution (that I've found) in dealing with UISearchController madness, or even the UISearchDisplayController of yesteryear, for that matter. They are worse in a UISplitViewController that is in collapsed mode, but many other layout bugs have long existed, dealing with everything from orientation to status bar neglect, and on and on.
But, you can get most of the way there with workarounds that I believe are, at least, futureproof. If you defer setting the navigationItem.searchController from viewDidLoad, until viewDidAppear, you circumvent the confusion that UISplitViewController has about WHICH nav item is currently its topmost item, and it will be correctly assigned to the right view controller. That seems to be the root issue. This is what I do in viewDidAppear...
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if (IS_OS_11_OR_LATER){
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpartial-availability"
if (!self.navigationItem.searchController){
self.navigationItem.searchController = self.searchController;
}
#pragma clang diagnostic pop
}
}
This ensures the search controller gets assigned to the correct nav item when the split view is collapsed. Once you're past this hurdle, it should remain permanently tacked to the correct nav item, and overcome the bug you've seen.
But, if you have the search bar permanently visible by setting self.navigationItem.hidesSearchBarWhenScrolling to NO, this will leave an empty gap where the search bar is supposed to be. If you drag the table view down a bit and back up, it will reappear. But, of course, that's not a winner. So, what I do is, when I create my search controller in viewDidLoad, I set self.navigationItem.hidesSearchBarWhenScrolling to YES, so that it's hidden, and the user never knows it isn't there until a table drag, because they have to drag to see it. Then, in the search delegate method, I set these to what I want them to be:
-(void)willPresentSearchController:(UISearchController *)searchController{
if (IS_OS_11_OR_LATER){
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpartial-availability"
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.navigationItem.hidesSearchBarWhenScrolling = NO;
#pragma clang diagnostic pop
}
}
This works for me. Given my druthers, I'd like the search bar visible when appearing. But - I have to pick my battles. I just include a search bar button item in the toolbar so user knows that search is available, and set isActive to YES when tapped. If you don't like that, you could hack it a bit further, and forgo creating the search controller in viewDidLoad, and instead create it from scratch in viewDidAppear EACH TIME. Doing it that way, for whatever reason, ensures that it is always visible without forcing the user to drag the table view. But, you'd lose the definesPresentationContext functionality. That's a little too much hacking for me, though, but your mileage may vary.
I've been fighting with search controllers since at least iOS 7 or 8. Each release brings a new bag of woes. I really wish Apple would devote some time into debugging them.
Danny