Home > Software engineering >  Programmatically embedding in navigation controller (Xcode 14.2, io2 16 )
Programmatically embedding in navigation controller (Xcode 14.2, io2 16 )

Time:01-25

I had a working program consisting basically of a table view controller embedded in a navigation controller, and I decided to try to get rid to some mysterious/obnoxious warnings that first appeared in iOS 16 ("UINavigationBar decoded as unlocked for UINavigationController, or navigationBar delegate set up incorrectly"). Following online suggestions, I got rid of the navigation controller on the storyboard, and added some code to

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        window?.windowScene = windowScene
        window?.makeKeyAndVisible()

// ViewController: UITableViewController is my VC class
        let viewController = ViewController()
        let navViewController = UINavigationController(rootViewController: viewController)
        window?.rootViewController = navViewController
    }

to embed it programmatically. The program would then crash with a message that stating that it could not deque a cell with identifier "itemCell", and "must register a nib or a class for the identifier or connect a prototype cell in a storyboard". I solved that by adding the line

self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "itemCell")

in ViewDidLoad but I don't understand why this was necessary, since the identifier for the prototype cell is still there in the storyboard, just as it was before. Can someone illuminate me? Thanks.

CodePudding user response:

This:

   let viewController = ViewController()
   let navViewController = UINavigationController(rootViewController: viewController)
   window?.rootViewController = navViewController

won't give you what you want.

In Storyboard, you have to give ViewController a Storyboard ID (such as "FirstViewController"), then instantiate it via code:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "FirstViewController")
let navViewController = UINavigationController(rootViewController: initialViewController)

Edit

Assuming the view controller we ID as "FirstViewController" in Storyboard is a table view controller, and we want to load it as the "root" controller for a navigation controller, the full code block would be:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    window?.windowScene = windowScene

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let initialViewController = storyboard.instantiateViewController(withIdentifier: "FirstViewController")
    let navViewController = UINavigationController(rootViewController: initialViewController)

    window?.rootViewController = navViewController

    window?.makeKeyAndVisible()
}
  • Related