I fixed the crash by setting initially secondary, controller at the same time as primary and compact controllers.
So I had a custom class
class SplitController: UISplitViewController {
override init(style: UISplitViewController.Style) {
super.init(style: style)
setupAppearance()
}
	 // ....
	private func setupAppearance() {
delegate = self
setViewController(sidebar, for: .primary)
setViewController(TabBarController(rootTabs: rootTabs), for: .compact)
}
}
and a sidebar had this implementation:
class SideBarController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// ...
splitViewController?.setViewController(mycontroller, for: .secondary)
}
}
And whenever I was launching app with compact controller, it would crash when expanding to regular mode.
I solved it by modifying setupAppearance method to:
	private func setupAppearance() {
delegate = self
setViewController(sidebar, for: .primary)
setViewController(homeController, for: .secondary)
// or even, if you really don't care for some reason
// setViewController(UIViewController(), for: .secondary)
setViewController(TabBarController(rootTabs: rootTabs), for: .compact)
}
Post
Replies
Boosts
Views
Activity
If you are looking for more verbose solution:
I believe the protocol Restorable mentioned in the vid is supposed to be written by you. You would have to wait for callback to splitViewController:topColumnForCollapsingToProposedTopColumn: method. When this method is called it is up to you, to retrieve current hierarchy from split view controller and apply it to tab bar controller.
For example I use something like this:
func splitViewController(_ svc: UISplitViewController,
	topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column) -> UISplitViewController.Column {
if proposedTopColumn == .compact,
	 let compactController = viewController(for: .compact) as? NavigationRestorable {
compactController.restoreHierarchy(from: currentHierarchy, selectedTab: selectedTab)
}
return proposedTopColumn
}
NOTE: NavigationRestorable is another protocol, which contain restoreHierarchy method and selectedTab property in my project, for you it may be a different set of value that is needed to restore state.
and implementation of restoreHierarchy method in any UITabBarController subclass would be similar to this.
func restoreHierarchy(from hierarchy: [HierarchyRestorableObject], selectedTab: Tab) {
setViewControllers(hierarchy.map({ $0.restore() }), animated: false)
/// update `selectedIndex` based on your `selectedTab` value.
}
NOTE: HierarchyRestorableObject - most likely would be a view controller, or a tuple of values where view controller would be.
then you would conform your view controller, to Restorable protocol
class MyController: UIViewController, Restorable {
// ...
func restore() -> UIViewController {
let restoredController = UIViewController(nibName: nil, bundle: nil)
// ... restore search state or even scroll position if needed
return restoredController
}
}
and then you can simple conform UINavigationController to Restorable protocol
extension UINavigationController: Restorable {
func restore() -> UIViewController {
let navController = NavigationController(navigationBarClass: NavigationBar.self, toolbarClass: nil)
navController.tabBarItem = tabBarItem
for viewController in viewControllers {
guard let restorableController = viewController as? Restorable else {
break
}
restoredNavigationController.pushViewController(restorableController.restore(), animated: false)
}
return navController
}
}
and that would be the entire solution. Unfortunately you would have to conform every of your view controllers to Restorable, and restore their unique state.
And do not worry about controller that are shown using present method.