A user of my app, whose main view is a split view, reported an issue which causes the left navigation bar items to disappear without apparent reason if they rotate the device and later show the detail view, preventing them from using the back button to show the root view again.
Am I doing something wrong or is it a bug?
I can reproduce the issue with the following steps:
- Create a new document-based iOS app (as it uses scenes by default, as opposed to a regular app).
- Paste the code below.
- In the target build settings, delete "Launch Screen Interface File Base Name" and set "Launch Screen (Generation)" to YES. Without this step, for some reason, the issue doesn't happen.
- Launch the app in iPhone Simulator.
- Tap the top left button to show the root view, then the “detail” button to show the detail view. The left navigation bar button is still visible.
- Rotate the Simulator window right, then left again.
- Tap the top left button to show the root view, then the “detail” button to show the detail view. Now the left navigation bar button is invisible. Rotating the device right and left again solves the issue.
I filed FB22363118.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
window = UIWindow(windowScene: scene as! UIWindowScene)
let split = SplitViewController()
window!.rootViewController = split
window!.makeKeyAndVisible()
split.showDetail()
}
}
class SplitViewController: UISplitViewController, UISplitViewControllerDelegate {
var detailNavigationViewController: UINavigationController!
init() {
super.init(nibName: nil, bundle: nil)
detailNavigationViewController = UINavigationController(rootViewController: DetailViewController())
viewControllers = [UINavigationController(rootViewController: RootViewController())]
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func showDetail() {
showDetailViewController(detailNavigationViewController, sender: nil)
}
func showRoot() {
(viewControllers.first as? UINavigationController)?.popViewController(animated: true)
}
}
class RootViewController: UIViewController {
override func loadView() {
navigationItem.title = "root"
let button = UIButton(primaryAction: UIAction(handler: { [self] _ in
(splitViewController as! SplitViewController).showDetail()
}))
button.setTitle("detail", for: .normal)
view = button
}
}
class DetailViewController: UIViewController {
override func loadView() {
navigationItem.title = "detail"
view = UIView()
registerForTraitChanges([UITraitHorizontalSizeClass.self]) { (self: Self, previousTraitCollection) in
if previousTraitCollection.horizontalSizeClass != self.traitCollection.horizontalSizeClass {
self.updateBarButtons()
}
}
updateBarButtons()
}
private func updateBarButtons() {
navigationItem.leftBarButtonItem = UIBarButtonItem(primaryAction: UIAction(image: UIImage(systemName: "sidebar.leading")) { [self] _ in
(self.splitViewController as! SplitViewController).showRoot()
})
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "right")
}
}