Search code examples
iosswiftxcodeuiviewcontrollerswift4

presenting whose view is not in the window hierarchy warning


I am new in Programming and swift, and I have tried to read some solutions in stack overflow, but to be honest I don't really grasp with the answer :(

I have 2 view controllers. a homeVC and a LoginVC. homeVC is my initial view controller. in viewDidLoad I have firebase function that can check if the user has logged in before or not. if not, then the user will be send to loginVC. here is my simplified code in the HomeVC

import UIKit
import Firebase


class HomeVC: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // to check whether the user has already logged in or not
        Auth.auth().addStateDidChangeListener { (auth, user) in
            if user == nil {
                let login = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginVC
                self.present(login, animated: true, completion: nil)
            }
        }

        print("user enter homeVC")

    }



}

and here is my loginVC

import UIKit
import Firebase
import GoogleSignIn

class LoginVC : UIViewController, GIDSignInUIDelegate {

    @IBOutlet weak var googleButton: GIDSignInButton!
    @IBOutlet weak var emailButton: UIButton!



    override func viewDidLoad() {
        super.viewDidLoad()


         // delegate declaration
         GIDSignIn.sharedInstance().uiDelegate = self

    }

    @IBAction func googleButtonDidPressed(_ sender: Any) {
        GIDSignIn.sharedInstance().signIn()
    }




}

the app can perform as I expected. but there is a warning in my debugging area :

Warning: Attempt to present LoginVC: 0x7fc315714f40 on HomeVC: 0x7fc3155095c0 whose view is not in the window hierarchy!

of course the problem is in this lines of code

let login = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginVC
self.present(login, animated: true, completion: nil)

as far as I know, if the view is stacked in the layer of navigation controller, then if I want to move to another view controller I have to use perform segue method.

But for this case, between homeVC and LoginVC are not stacked in the same navigation controller. so no hierarchy. thats why I use that line of code to move to another view controller (loginVC). but I don't understand why it is said "view is not in the window hierarchy!"

So what should I do to omit that warning?


Solution

  • Your LoginVC is perfectly fine.

    However, you need to change your HomeVC as @Sh_Khan suggested and move the testing code from viewDidLoad to viewDidAppear:

    import UIKit
    import Firebase
    
    class HomeVC: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        
        // HomeVC.view was added to a view hierarchy
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            
            // to check whether the user has already logged in or not
            Auth.auth().addStateDidChangeListener { (auth, user) in
                if user == nil {
                    let login = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginVC
                    self.present(login, animated: true, completion: nil)
                }
            }
        }
    }
    

    Explanation

    Your viewDidLoad method gets called before the viewController gets presented, so it at that moment it cannot really present another view controller (since it itself is not presented), viewDidLoad documentation:

    Called after the controller's view is loaded into memory.

    This method is called after the view controller has loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy was loaded from a nib file or created programmatically in the loadView() method. You usually override this method to perform additional initialization on views that were loaded from nib files.

    In that moment the viewController is not in the window hierarchy yet.

    viewDidAppear however gets called when the view is presented and becomes a part of the window hierarchy, viewDidAppear documentation:

    Notifies the view controller that its view was added to a view hierarchy.

    You can override this method to perform additional tasks associated with presenting the view. If you override this method, you must call super at some point in your implementation.

    Don't forget to call super.viewDidAppear during overriding it.