我是编程和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)。但我不明白为什么说“视图不在窗口层次结构中!”
那么我应该怎么做才能省略这个警告?
答案 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
答案 5 :(得分:0)
此时,在代码中,视图控制器的视图仅已创建,但未添加到任何视图层次结构中。如果您希望尽快从该视图控制器中进行显示,则应在viewDidAppear中这样做是最安全的。