显示其视图不在窗口层次结构中警告

时间:2018-01-18 11:20:59

标签: ios swift xcode uiviewcontroller swift4

我是编程和swift的新手,我试图在堆栈溢出中读取一些解决方案,但说实话我并没有真正掌握答案:(

我有2个视图控制器。 homeVC和LoginVC。 homeVC是我的初始视图控制器。在viewDidLoad我有firebase功能,可以检查用户之前是否登录过。如果没有,那么用户将被发送到loginVC。这是我在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")

    }



}

这是我的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()
    }




}

该应用可以按预期执行。但我的调试区域有一个警告:

  

警告:尝试提供LoginVC:0x7fc315714f40   HomeVC:0x7fc3155095c0,其视图不在窗口中   层次!

当然问题在于这行代码

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

据我所知,如果视图堆叠在导航控制器层中,那么如果我想移动到另一个视图控制器,我必须使用perform segue方法。

但是对于这种情况,homeVC和LoginVC之间没有堆叠在同一个导航控制器中。所以没有等级。这就是为什么我使用那行代码移动到另一个视图控制器(loginVC)。但我不明白为什么说“视图不在窗口层次结构中!”

那么我应该怎么做才能省略这个警告?

6 个答案:

答案 0 :(得分:3)

将代码移至viewDidAppear

 override func viewDidAppear()
 {
  // 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")

}

答案 1 :(得分:2)

TLDR;您应该将代码移动到viewDidAppear

<强> viewDidLoad中()

  

在视图控制器将其视图层次结构加载到内存后调用此方法。无论视图层次结构是从nib文件加载还是在loadView()方法中以编程方式创建,都会调用此方法。您通常会覆盖此方法以对从nib文件加载的视图执行其他初始化。   Apple docs

因此视图仅在内存中而不在层次结构中。您应该将其移至viewDidAppear

viewDidAppear()

  

通知视图控制器其视图已添加到视图层次结构中。 Apple docs

答案 2 :(得分:1)

你的LoginVC完全没问题。

但是,您需要将HomeVC更改为@Sh_Khan建议,并将测试代码从viewDidLoad移至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)
            }
        }
    }
}

<强>解释

您的viewDidLoad方法会在viewController出现之前被调用,因此它在那时它无法真正呈现另一个视图控制器(因为它本身未呈现),viewDidLoad documentation:< / p>

  

在控制器的视图加载到内存后调用。

     

在视图控制器将其视图层次结构加载到内存后调用此方法。无论视图层次结构是从nib文件加载还是在loadView()方法中以编程方式创建,都会调用此方法。您通常会覆盖此方法以对从nib文件加载的视图执行其他初始化。

在那一刻,viewController还没有进入窗口层次结构。

viewDidAppear会在view出现并成为窗口层次结构viewDidAppear documentation的一部分时被调用:

  

通知视图控制器其视图已添加到视图层次结构中。

     

您可以覆盖此方法以执行与显示视图相关的其他任务。如果重写此方法,则必须在实现中的某个时刻调用super。

请勿忘记在覆盖期间致电super.viewDidAppear

答案 3 :(得分:1)

正如Sh_Khan所说,移动线条:

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

在viewDidAppear()方法中;调用viewDidLoad()时,视图控制器尚未添加到视图层次结构中,它不可见,并且不能显示另一个视图控制器。

答案 4 :(得分:1)

出现这种错误的原因是:您正在尝试同时显示(打开)两个视图控制器(第一个呈现视图控制器的视图刚刚启动,您可能正在尝试呈现第二个视图控制器)。

您应该将代码(用于视图控制器演示/导航)移动到viewDidAppear。您现有视图控制器的主视图(从您呈现新视图控制器的位置)尚未准备好/已加载。

您应将其移至viewDidAppear

以下是示例代码:

Swift 4

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // instantiate your view controller either using storyboard or class or any other way....
    if let newVC = self.storyboard?.instantiateViewController(withIdentifier: "NewViewController") as? NewViewController {
         self.present(newVC, animated: true, completion: nil)
    }
}

在您的案例/代码中,解决方案是:

override func viewDidLoad() {
    super.viewDidLoad()

     // Move your code from here (viewDidLoad) to viewDidAppear

}

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)
        }
    }

    print("user enter homeVC")

}

查看两个视图控制器生命周期之间的区别。

<强> viewDidLoad

  

在视图控制器将其视图层次结构加载到内存后调用此方法。无论视图层次结构是从nib文件加载还是在loadView()方法中以编程方式创建,都会调用此方法。您通常会覆盖此方法以对从nib文件加载的视图执行其他初始化。   
查看更多关于:viewDidLoad

的信息

viewDidAppear

  

通知视图控制器其视图已添加到视图层次结构中。   
查看更多关于:viewDidAppear

的信息

答案 5 :(得分:0)

此时,在代码中,视图控制器的视图仅已创建,但未添加到任何视图层次结构中。如果您希望尽快从该视图控制器中进行显示,则应在viewDidAppear中这样做是最安全的。