I have a UISplitViewController with two UINavigationControllers as primary and detail view controllers, created using Storyboard. The primary has a static UITableViewController and clicking on a row would set the detail view to load in the detail view navigation controller.
Everything is working as expected, except when I set overrideUserInterfaceStyle to "dark mode". When that is done, the UISplitViewController's viewControllers array has only 1 element in it - the primary view controller.
I tried to recreate the problem using a simplified example, and succeeded in reproducing the issue.
The reproducible test case is at https://github.com/sridharrajagopal/TestApp
protocol RootSettingsViewControllerSelectionDelegate : AnyObject {
func viewControllerSelected(_ vc: String)
}
class RootSettingsViewController: UITableViewController, MFMailComposeViewControllerDelegate {
weak var delegate: RootSettingsViewControllerSelectionDelegate?
override func viewDidLoad() {
super.viewDidLoad()
if (UIDevice.current.userInterfaceIdiom == .pad) {
let indexPath = IndexPath(row: 0, section: 0)
tableView.selectRow(at: indexPath, animated: true, scrollPosition: UITableView.ScrollPosition.top)
tableView.delegate?.tableView!(tableView, didSelectRowAt: indexPath)
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (indexPath.section == 2 && indexPath.row == 2) {
// emailUs()
} else if (indexPath.section == 0 && indexPath.row == 0) {
delegate?.viewControllerSelected("A")
} else if (indexPath.section == 0 && indexPath.row == 1) {
delegate?.viewControllerSelected("B")
} else if (indexPath.section == 0 && indexPath.row == 2) {
delegate?.viewControllerSelected("C")
}
if let detailViewController = delegate as? SettingsSecondaryNavigationViewController {
splitViewController?.showDetailViewController(detailViewController, sender: nil)
}
}
}
class SettingsSecondaryNavigationViewController: UINavigationController {
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension SettingsSecondaryNavigationViewController: RootSettingsViewControllerSelectionDelegate {
func viewControllerSelected(_ vc: String) {
if (vc == "A") {
let detailViewController = UIViewController()
detailViewController.view.backgroundColor = .red
self.viewControllers = [detailViewController]
} else if (vc == "B") {
let detailViewController = UIViewController()
detailViewController.view.backgroundColor = .green
self.viewControllers = [detailViewController]
} else if (vc == "C") {
let detailViewController = UIViewController()
detailViewController.view.backgroundColor = .blue
self.viewControllers = [detailViewController]
} else if (vc == "D") {
let detailViewController = UIViewController()
detailViewController.view.backgroundColor = .purple
self.viewControllers = [detailViewController]
}
}
}
class SettingsSplitViewController: UISplitViewController, UISplitViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
let detailViewController =
(self.viewControllers.last as? SettingsSecondaryNavigationViewController)
let primaryViewController =
(self.viewControllers.first as? UINavigationController)?
.topViewController as? RootSettingsViewController
// This is where it bombs, as detailViewController is nil
primaryViewController!.delegate = detailViewController!
preferredDisplayMode = UISplitViewController.DisplayMode.oneBesideSecondary
}
func splitViewController(
_ splitViewController: UISplitViewController,
collapseSecondary secondaryViewController: UIViewController,
onto primaryViewController: UIViewController
) -> Bool {
return true
}
}
I am quite stumped at this time. If overrideUserInterfaceStyle is .light or .unspecified (match system settings), everything's working fine.
I see that when loading the app, the SettingsSecondaryNavigationViewController's viewDidLoad gets called when overrideUserInterfaceStyle is .light or .unspecified (even before loading the actual UISplitViewController, but doesn't get called when .dark mode.
My first question is if what I'm doing is ok, or has some inherent problems that's manifesting as the "dark mode" issue.
Any insights or pointers would be greatly appreciated!
I have filed a bug report with Apple.
I have worked around the issue by creating the primary and detail view controllers programmatically in the UISplitViewController’s viewDidLoad using the storyboard ID to load the viewControllers from the Interface Builder storyboard.