Swift segue not working, unexpectedly found nil

Whenever I perform a segue to my SignUpViewController there is an error that says unexpectedly found nil when unwrapping an optional value in the view did load, here is my code.

SignUpViewController:





Here is the view controller I am performing the segue from:

Code Block Swift
import UIKit
class MainViewController: UINavigationController {
  override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .white
     
    if isLoggedIn(){
      let tabBarController = TabBarViewController()
      viewControllers = [tabBarController]
    }else{
      perform(#selector(showLoginController), with: nil, afterDelay: 0.01)
    }
  }
   
  fileprivate func isLoggedIn() -> Bool {
    return UserDefaults.standard.isLoggedIn()
  }
   
  @objc func showLoginController() {
    let loginController = LoginViewController()
    present(loginController, animated: true, completion: {
       
    })
  }
}



Answered by OOPer in 666214022
Seems your code causes error when you show LoginViewController, not when segue to SignUpViewController.
(You should better show on which line the error is shown, that may prevent misunderstanding.)

This line is the worst part of your code:
Code Block
    let loginController = LoginViewController()


When you create a design of a view controller using storyboard, calling initializer init() like LoginViewController() just creates a garbage object which causes unexpectedly found nil and would never work.

Why don't you use instantiateViewController(identifier:) as you do in LoginViewController:
Code Block
class MainViewController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
if isLoggedIn() {
//#↓ If `TabBarViewController` does not suit for `init()` this may cause problems
let tabBarController = TabBarViewController()
viewControllers = [tabBarController]
} else {
//# I do not understand why you put 0.01 sec delay,
//# but you should better not use `perform(_:with:afterDelay:)`
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
self.showLoginController()
}
}
}
fileprivate func isLoggedIn() -> Bool {
return UserDefaults.standard.isLoggedIn()
}
private func showLoginController() {
//#↓ When you instantiate a view controller desinged on the storyboard,
//# you should use `instantiateViewController(identifier:)`
guard let loginController = self.storyboard?.instantiateViewController(identifier: "loginVC") as? LoginViewController //#<- Replace `"loginVC"` to the right Storyboard ID
else {
print("Storyboard is not configured as expected")
return
}
present(loginController, animated: true, completion: {
//# If you do nothing here, you can pass `nil` to `completion:`
})
}
}

(Put a Storyboard ID to LoginViewController, and use it in instantiateViewController(identifier:).


I haven't checked other parts of your code. If this does not work, please tell me with detailed description.
Accepted Answer
Seems your code causes error when you show LoginViewController, not when segue to SignUpViewController.
(You should better show on which line the error is shown, that may prevent misunderstanding.)

This line is the worst part of your code:
Code Block
    let loginController = LoginViewController()


When you create a design of a view controller using storyboard, calling initializer init() like LoginViewController() just creates a garbage object which causes unexpectedly found nil and would never work.

Why don't you use instantiateViewController(identifier:) as you do in LoginViewController:
Code Block
class MainViewController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
if isLoggedIn() {
//#↓ If `TabBarViewController` does not suit for `init()` this may cause problems
let tabBarController = TabBarViewController()
viewControllers = [tabBarController]
} else {
//# I do not understand why you put 0.01 sec delay,
//# but you should better not use `perform(_:with:afterDelay:)`
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
self.showLoginController()
}
}
}
fileprivate func isLoggedIn() -> Bool {
return UserDefaults.standard.isLoggedIn()
}
private func showLoginController() {
//#↓ When you instantiate a view controller desinged on the storyboard,
//# you should use `instantiateViewController(identifier:)`
guard let loginController = self.storyboard?.instantiateViewController(identifier: "loginVC") as? LoginViewController //#<- Replace `"loginVC"` to the right Storyboard ID
else {
print("Storyboard is not configured as expected")
return
}
present(loginController, animated: true, completion: {
//# If you do nothing here, you can pass `nil` to `completion:`
})
}
}

(Put a Storyboard ID to LoginViewController, and use it in instantiateViewController(identifier:).


I haven't checked other parts of your code. If this does not work, please tell me with detailed description.
Thanks, this worked
Swift segue not working, unexpectedly found nil
 
 
Q