1

My ViewDidLoad method on a ViewController is called twice, but only in a particular scenario. There are two view controllers which I need to present, one if user isn't logged in and the second if the user is logged in. I am using storyboard and have set a navigation controller as initial view controller in it.

In my AppDelegate didFinishLaunchingWithOptions method I have populated ViewControllers array with the desired controller as below

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController = storyboard.instantiateViewController(withIdentifier: "navController") as! UINavigationController
if UserDefaults.standard.object(forKey: USERID) != nil {
    viewController = storyboard.instantiateViewController(withIdentifier: "HomeVC_ID") as! HomeVC
} 
else {
    viewController = storyboard.instantiateViewController(withIdentifier: "LoginVC_ID") as! LoginVC
}
navigationController.viewControllers = [viewController] as! [UIViewController]
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()

ViewDidLoad method in HomeVC is called twice, whereas it's called just once for LoginVC.

I already tried searching through articles viewDidLoad is called twice and viewDidLoad getting called twice on rootViewController at launch but couldn't corner the issue.

Denis
  • 492
  • 2
  • 15
Sam
  • 521
  • 1
  • 6
  • 23
  • 1
    I think this is due to segue in Storyboard. – Rizwan Nov 19 '18 at 08:11
  • I have ticked "Is Initial View Controller" for navigation controller. No other segue used. If I remove it, it shows a black screen on loading. – Sam Nov 19 '18 at 08:16
  • if you setting root view controller programmatically then remove main interface from Deployment Info. – Jatin Kathrotiya Nov 19 '18 at 08:20
  • Maybe the `UITabViewController` is better for your UI design. You can hide tab button and control it by codes. – AechoLiu Nov 19 '18 at 09:28
  • @JatinKathrotiya Removing "Main Storyboard file base name" presents a black screen after splash. – Sam Nov 19 '18 at 10:00
  • need to create window inside didFinishLaunchingWithOptions `self.window = UIWindow(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height))` – Jatin Kathrotiya Nov 19 '18 at 10:10
  • thanks @JatinKathrotiya Its working. but the issue remains, viewDidLoad still called twice. – Sam Nov 19 '18 at 10:31
  • if navigation controller has rootview controller inside story board then remove it – Jatin Kathrotiya Nov 19 '18 at 10:39
  • you have set embedded homeVC is initial ViewController on storyboard. Do not embed you homeVc in navigationController. Because When app launches it instantiated once from storyboard and second time from appDelegate. – Abu Ul Hassan Nov 19 '18 at 11:14
  • I removed the navigation controller from storyboard. Implemented it programmatically from appdelegate. Still HomeVC viewDidLoad called twice on first launch. – Sam Nov 19 '18 at 11:30

2 Answers2

3

When you create your navigation view controller from the storyboard, this already contains it's rootViewController (which must not to be confused with the rootViewController of the UIWindow). I guess this is your HomeVC (in the storyboard). So, the storyboard magic already creates HomeVC, and you do not have to create it manually in didFinishLaunchingWithOptions.

If you have specify the storyboard as your main interface in the project's/target's properties, you do not need any creational code in didFinishLaunchingWithOptions and just let the framework perform the magic.

If you want to do this programatically, then - in the storyboard - you should remove the navigation controller, and create it manually (not via instantiateViewController) in didFinishLaunchingWithOptions. You would also add the appropriate root view controller here (instantiated from the storyboard), maybe like this:

let storyboard = UIStoryboard(name: "Main", bundle: nil)

if UserDefaults.standard.object(forKey: USERID) != nil {
    viewController = storyboard.instantiateViewController(withIdentifier: "HomeVC_ID") as! HomeVC
} else {
    viewController = storyboard.instantiateViewController(withIdentifier: "LoginVC_ID") as! LoginVC
}
let navigationController = UINavigationController(rootViewController:viewController)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
Andreas Oetjen
  • 9,889
  • 1
  • 24
  • 34
  • thanks. I removed navigation controller from storyboard and created the same manually, but the issue still repeats. On auto-login when control directly goes to the HomeVC, viewDidLoad is called just once, as desired. But in case of first time login, when it navigates from LoginVC, then its called twice. – Sam Nov 19 '18 at 11:07
0

I would recommend don't do any manual segue OR load view controller in app delegate. Use following piece of code in viewDidLoad of LoginView (hoping this is root view of your app always).

Use segue for login to homeview.

if UserDefaults.standard.object(forKey: USERID) != nil {
     self.performSegue(withIdentifier: "HomeViewIdentifier", sender: self)
}

Considering HomeViewIdentifier is a segueId for LoginView to HomeView. Why I am suggesting this because you need to segue back to loginView when user logs out. In case you make homeView as rootview then where will you go in case of logout.

Rizwan
  • 3,324
  • 3
  • 17
  • 38