【问题标题】:View Controller not instantiating inside IF statement视图控制器未在 IF 语句中实例化
【发布时间】:2018-10-27 19:26:03
【问题描述】:

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

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

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

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

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

这里是 switcher.swift

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
    }

【问题讨论】:

标签: swift firebase firebase-realtime-database viewcontroller


【解决方案1】:

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

使用异步调用,您传入的代码在函数调用返回时将永远不会运行,然后您将继续应用中的下一步。

因此你不能做你想做的事。当您在 if/else 块之后访问 appDelegate 代码时,您的 rootVC 变量将为零。

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

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

编辑:

创建一个视图控制器。称它为 ContainerViewController。在启动时将其安装为窗口的根视图控制器。给那个视图控制器一个容器视图。设置该视图控制器的 viewDidLoad() 以调用 firebase 调用,并在 firebase 调用的完成处理程序中决定要实例化哪种类型的视图控制器,并将该视图控制器安装在容器视图中。

【讨论】:

  • 您能详细说明如何做到这一点吗?我有来自容器 VC 的代码,但我没有使用滑出式“汉堡”菜单。
  • @Greg 这个答案是正确的。我会建议另一种解决方案,让我澄清一下。 app:didFinishLaunching 函数中的语句return true 在根控制器建立之前 执行。换句话说,它在 appDelegate.window?.rootViewController = rootVC 运行之前被调用。另一种选择是在加载 rootController 之后从 Firebase 闭包中返回 true。它必须重新编码,但它可以遵循以下语句 appDelegate.window?.rootViewController = rootVC
  • @Jay Jay,感谢您的建议。实际上,我确实在两个关闭语句下都返回了 true,但它只使用了第一个。我的意思是,在我的代码中,您会看到我正在寻找一个假值,因此要基于假实例化视图控制器。当我进入 firebase 并将该值设为 true 时,它​​仍然执行第一个值,因为那是 return 是。我将使用返回来重新编写代码。我假设你的意思是我应该在 if/else 下都有回报。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-20
  • 1970-01-01
  • 1970-01-01
  • 2016-08-23
  • 1970-01-01
相关资源
最近更新 更多