【问题标题】:presenting whose view is not in the window hierarchy warning显示其视图不在窗口层次结构警告中
【发布时间】:2018-06-27 10:55:03
【问题描述】:

我是编程和 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 on HomeVC: 0x7fc3155095c0 其视图不在窗口中 等级制度!

当然问题出在这行代码

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

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

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

那么我应该怎么做才能忽略该警告?

【问题讨论】:

  • viewDidLoad 中的视图尚未准备好。在 viewDidAppear 中尝试相同的代码

标签: ios swift xcode uiviewcontroller swift4


【解决方案1】:

将代码移动到 viewDidAppear

 override func viewDidAppear(_ animated:Bool) {
    super.viewDidAppear(true)
  // 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")

}

【讨论】:

    【解决方案2】:

    您的LoginVC 非常好。

    但是,您需要按照@Sh_Khan 的建议更改您的HomeVC,并将测试代码从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

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

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

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

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

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

    您可以重写此方法来执行与呈现视图相关的其他任务。如果你重写了这个方法,你必须在你的实现中调用 super。

    在覆盖它时不要忘记调用super.viewDidAppear

    【讨论】:

      【解决方案3】:

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

      viewDidLoad()

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

      所以视图只在内存中,而不在层次结构中。你应该把它移到 viewDidAppear

      viewDidAppear()

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

      【讨论】:

        【解决方案4】:

        正如 Sh_Khan 所说,移动线条:

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

        在 viewDidAppear() 方法中;当 viewDidLoad() 被调用时,它还没有添加到视图层次结构中的视图控制器,它是不可见的,它不能呈现另一个视图控制器。

        【讨论】:

          【解决方案5】:

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

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

          你应该把它移到viewDidAppear


          这里是示例代码:

          斯威夫特 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

          【讨论】:

            【解决方案6】:

            此时,在您的代码中,仅创建了视图控制器的视图,但未将其添加到任何视图层次结构中。如果您想尽快从该视图控制器呈现,您应该在 viewDidAppear 中进行以最安全。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-08-07
              • 1970-01-01
              相关资源
              最近更新 更多