Swift 视图控制器未在IF语句中实例化

Swift 视图控制器未在IF语句中实例化,swift,firebase,firebase-realtime-database,viewcontroller,Swift,Firebase,Firebase Realtime Database,Viewcontroller,我正在设计一个应用程序,当用户第一次打开它并且他们当前已登录时,我希望它对他们的数据进行快照,然后根据条件实例化一个视图控制器 在我的示例中,如果用户是“驱动程序”,意味着firebase中的值是“true”,那么我希望他们转到“驱动程序”视图控制器。如果用户不是“驱动程序”,那么我希望他们转到“用户”视图控制器(TabBarVC)。如果用户为零或未登录,则会转到登录VC 我已经在没有条件的情况下测试了代码。如果用户已登录(无快照),则转到TabBarVC;如果用户已注销,则转到Login VC

我正在设计一个应用程序,当用户第一次打开它并且他们当前已登录时,我希望它对他们的数据进行快照,然后根据条件实例化一个视图控制器

在我的示例中,如果用户是“驱动程序”,意味着firebase中的值是“true”,那么我希望他们转到“驱动程序”视图控制器。如果用户不是“驱动程序”,那么我希望他们转到“用户”视图控制器(TabBarVC)。如果用户为零或未登录,则会转到登录VC

我已经在没有条件的情况下测试了代码。如果用户已登录(无快照),则转到TabBarVC;如果用户已注销,则转到Login VC

在使用该条件运行应用程序时,应用程序崩溃,并说“应用程序窗口应在应用程序启动结束时具有根视图控制器”,这对我来说意味着它在使用FireBase快照中的条件时没有读取我的代码

请让我知道我做错了什么,我认为“rootVC”会起作用,因为它是一个以“var rootVC:UIViewController?的形式出现的变量

这是斯威夫特

import Foundation
import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase

class Switcher {
    static func updateRootVC() {

        var rootVC : UIViewController?

        let currentUser = Auth.auth().currentUser?.uid

        if Auth.auth().currentUser != nil{
            DataService.instance.REF_USERS.child(currentUser!).observeSingleEvent(of: .value, with: { (snapshot) in
                if let userSnapshot = snapshot.children.allObjects as? [DataSnapshot] {
                    for user in userSnapshot {
                            if user.childSnapshot(forPath: "driver_profile/is_userdriver").value as? Bool == false {
                                rootVC = UIStoryboard(name: "Driver", bundle: nil).instantiateViewController(withIdentifier: "DriverHomeVC") as! DriverHomeVC
                            } else {
                                rootVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "TabBarVC")
                                return
                        }
                    }
                }
            })
         // rootVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "TabBarVC")
         // rootVC = UIStoryboard(name: "Driver", bundle: nil).instantiateViewController(withIdentifier: "DriverHomeVC") as! DriverHomeVC

        }else{
            rootVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginVC") as! LoginVC

        }

        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.window?.rootViewController = rootVC

    }
}
以下是AppDelegate.swift的一部分,以防您需要了解如何调用它:

import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
import FirebaseInstanceID


@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    override init() {

        FirebaseApp.configure()
        Database.database().isPersistenceEnabled = true
    }

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {



        Switcher.updateRootVC()

        return true
    }

我没有使用FireBase,但是您使用的方法,
observeSingleEvent(of:with:)
几乎肯定是一个异步事件。它会在数据库读取完成之前立即返回。您传入一个闭包(一段代码),一旦获取完成,调用就会运行该代码

对于异步调用,当函数调用返回并进入应用程序的下一步时,您传入的代码将永远不会运行

所以你不能做你想做的事。当您在if/else块之后到达appDelegate代码时,您的
rootVC
变量将为零

你需要找到一种不同的方式来做你正在做的事情

我建议创建一个在所有情况下都是相同类型的根视图控制器,并为其提供一个容器视图,一旦数据库获取完成,该视图将加载相应类型的子视图

编辑:
创建视图控制器。称之为ContainerViewController。在启动时将其安装为窗口的根视图控制器。为该视图控制器提供一个容器视图。设置视图控制器的
viewdiload()
以调用firebase调用,并在firebase调用的完成处理程序中,确定要实例化的视图控制器类型,然后在容器视图中安装该视图控制器。

您能否详细说明如何执行此操作?我有来自容器VC的代码,但我没有使用滑出式“汉堡包”菜单。@Greg这个答案很准确。我想提出另一个解决办法,让我澄清一下。app:didFinishLaunching函数中的语句返回true,在根控制器建立之前执行。换句话说,在appDelegate.window?.rootViewController=rootVC运行之前调用它。另一个选项是在加载rootController后从Firebase闭包中返回true。它需要重新编码一点,但可以遵循以下语句appDelegate.window?.rootViewController=rootVC。@Jay,谢谢你的建议。我确实在两个闭包语句下都返回了true,但只使用了第一个。我的意思是,在我的代码中,您将看到我正在寻找一个假值,因此要基于假值实例化视图控制器。当我进入firebase并使该值为真时,它仍然执行第一个值,因为这是返回值。我将用返回的代码重新编写代码。我想你的意思是我应该在if/else下都有一个报税表。看看这个旧的但仍然相关的答案@Jay,我会查一下。