I have what seems to be a very common setup in my universal application, with a root UISplitViewController
, using a UITabBarController
as a masterViewController
, and then I want to:
- either push the detail view controller onto the stack if I'm on a vertical iPhone
- show the detail controller in the detailViewController of the
UISplitViewController
on lanscape iPhone 6+ and other larger screens like iPads and such
To that effect, I have exactly the same setup as the ones described in all those discussions that mention a similar issue:
- UINavigationController inside a UITabBarController inside a UISplitViewController presented modally on iPhone
- iOS8 TabbarController inside a UISplitviewController Master
- Adaptive show detail segue transformed to modal instead of push on iPhone when master view controller is a UITabBarController
But none of the solutions mentioned in those questions works. Some of them create an infinite recursive loop and an EXC_BAD_ACCESS
. And the latest one I tried simply keeps presenting the detail view controller modally instead of pushing it onto the stack on iPhones. What I did is create a custom UISplitViewController
subclass as such:
class RootSplitViewController: UISplitViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
}
extension RootSplitViewController: UISplitViewControllerDelegate {
func splitViewController(_ splitViewController: UISplitViewController, showDetail vc: UIViewController, sender: Any?) -> Bool {
if let tabController = splitViewController.viewControllers[0] as? UITabBarController {
if(splitViewController.traitCollection.horizontalSizeClass == .compact) {
tabController.selectedViewController?.show(vc, sender: sender)
} else {
splitViewController.viewControllers = [tabController, vc]
}
}
return true
}
func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
if let tabController = splitViewController.viewControllers[0] as? UITabBarController {
if let navController = tabController.selectedViewController as? UINavigationController {
return navController.popViewController(animated: false)
} else {
return nil
}
} else {
return nil
}
}
}
And here is the code in the master view controller to show the detail view controller:
self.performSegue(withIdentifier: "showReference", sender: ["tags": tags, "reference": reference])
Where tags
and reference
where loaded from Firebase. And of course the "showReference" segue is of the "Show Detail (e.g. Replace)" kind.
The first delegate method is called correctly, as evidenced by the breakpoint that gets hit there when I click an item in the list inside the UITabBarController
. And yet the detail view controller still presents modally on iPhone. No problem on iPad though: the detail view controller appears on the right, as expected.
Most of the answers mentioned above are pretty old and some of the solutions are implemented in Objective-C so maybe I did something wrong in the conversion, or something changed in the UISplitViewController
implementation since then.
Does anyone have any suggestion?