如何从 Firebase 检索数据,将其设置为全局变量,然后将其传递给下一个视图控制器?

How to retrieve data from Firebase, set it to a global variable, then pass it to the next view controller?

首先,这个问题是关于 iOS,而不是 android。希望它不会再次被标记为与 android 重复。

其次,为了解释清楚,这些是我对应用程序的意图 运行:

  1. 在 "shouldPerformSegueWithIdentifier"
  2. 内部执行检查
  3. 检查用户名和密码是否为空。如果为空,return false 并显示 alert

注意:我可以做到第 2 点。我知道如何从 firebase 检索数据。问题出在第3点之后。

  1. 否则,继续并比较 firebase 中的数据
  2. 如果找到匹配项,获取文档 ID 并将其设置为全局变量和 return TRUE,以便 prepareForSegue 方法能够 运行.
  3. 否则,return FALSE 并显示没有匹配凭证的警告

问题

我为堆栈溢出的解决方案做了很多研究,我理解它与异步相关,其中代码 OUTSIDE 首先 运行。但是,我找不到与 shouldPerformSegue 方法相关的单一解决方案。

虽然我尝试了 completionHandler 方法。但是,那段代码在那个方法里面不能return true or false,在return中无法确定是否应该执行segue。此外,只有当我需要将该用户 ID 传递给其他视图控制器时,才能在该方法中检索数据。

这是 shouldPerformSegueWithIdentifier 代码(请原谅我是否格式化,因为我通常不会在堆栈溢出中提问,但我无能为力,因为这让我很恼火,因为我找不到解决方案在一整天梳理堆栈溢出后到它。不过不要介意 "return true",因为我仍然需要同时访问其他视图控制器,因此,除了空检查之外,我将它设置为 return 目前为真。):

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
        let username : String = outUsername.text!
        let password : String = outPassword.text!
        if username.isEmpty && password.isEmpty {
            let alert = UIAlertController(title: "Error", message: "Username and/or password cannot be empty", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Close", style: .default, handler: nil))
            present(alert, animated: true, completion: nil)
            return false
        } else {
            db.collection("user").getDocuments() { (querySnapshot, err) in
                if err != nil {
                    print("Error getting documents")
                } else {
                    for document in querySnapshot!.documents {
                        let username02 : String = (document["username"] as? String)!
                        let password02 : String = (document["password"] as? String)!
                        if username02 == username && password02 == password {
                            self.userID = document.documentID
                        }
                    }
                }
            }
            return true
        }
    }

else 检查中的问题是:

你执行了一个异步任务,所以当你通过 else 检查时会发生什么是你之前 return truefirebase 检索数据。

所以您需要做的是使用 completionHandler 或一些通知并将函数 return 类型更改为 void,如下所示:


override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?, completionHandler:  @escaping ( _ shouldPerformSegue : Bool, _ userId : String) ->())  {
    let username : String = outUsername.text!
    let password : String = outPassword.text!
    if username.isEmpty && password.isEmpty {
        let alert = UIAlertController(title: "Error", message: "Username and/or password cannot be empty", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Close", style: .default, handler: nil))
        present(alert, animated: true, completion: nil)
        completionHandler(false,"")
    } else {
        db.collection("user").getDocuments() { (querySnapshot, err) in
            if err != nil {
                print("Error getting documents")
            } else {
                for document in querySnapshot!.documents {
                    let username02 : String = (document["username"] as? String)!
                    let password02 : String = (document["password"] as? String)!
                    if username02 == username && password02 == password {
                        completionHandler(true,document.documentID)

                    }else{ 
                        completionHandler(false,"")
                }
            }
        }
    }
}

我假设您在成功登录后已收到数据 (self.userID = document.documentID)。那么您可以通过多种方式使用该数据...

方法一:UserDefaults 成功登录后,将您的用户 ID 设置为 UserDefaults。喜欢

UserDefaults.standard.set(true, forKey: "userLoggedIn")
UserDefaults.standard.set(documentID, forKey: "userId")
UserDefaults.standard.synchronize()

和你的下一个家ViewController你可以回来,喜欢

UserDefaults.standard.bool(forKey: "userLoggedIn")  // true 
UserDefaults.standard.string(forKey: "userId")  //documentID

方法二:Segue

将收到的值设置为登录的全局变量 ViewController 并在 performSegue 中使用它。

打电话给你的 Segue

self?.performSegue(withIdentifier: "loginToMain", sender: self)

自动执行方法,将您的全局值设置为 homeViewController 变量。我假设 HomeViewController 有 var userID..

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

                if (segue.identifier == "loginToMain") {
                    if let target = segue.destination as? homeViewController
                    {
                        target.fromLogin = true
                        target.userId = self.userId
                    }
                }
    }

希望,它有帮助..

Whosebug 总是有用的

所以在尝试了很多天之后,终于能够正常运行了,虽然加载有点慢,但是现在可以了,因为它只是一个示例原型应用程序。如果你们中的任何人在从 Firebase 检索后遇到空人口并且需要将该数据传递给另一个控制器,我是这样做的:

来自按钮代码的 IBAction:

@IBAction func actLogin(_ sender: UIButton) {
    let username : String = outUsername.text!
    let password : String = outPassword.text!
    if username.isEmpty && password.isEmpty {
        let alert = UIAlertController(title: "Error", message: "Username and/or password cannot be empty", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Close", style: .default, handler: nil))
        present(alert, animated: true, completion: nil)
    } else {
        var userID : String = ""
        var recordFound : Bool = false
        db.collection("user").getDocuments() { (querySnapshot, err) in
            if err != nil {
                print("Error getting documents")
            } else {
                for document in querySnapshot!.documents {
                    let username02 : String = (document["username"] as? String)!
                    let password02 : String = (document["password"] as? String)!
                    if username02 == username && password02 == password {
                        userID = document.documentID
                        recordFound = true
                    }
                }
                if recordFound == true {
                    self.performSegue(withIdentifier: "nextCtrl", sender: userID)
                } else {
                    let alert = UIAlertController(title: "Error", message: "Please enter a valid account credential.", preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "Close", style: .default, handler: nil))
                    self.present(alert, animated: true, completion: nil)
                }
            }
        }
    }
}

准备 segue 方法:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let tabBarCtrller = segue.destination as? UITabBarController, let userID = sender as? String {
            // To retrieve from Firebase once user and password login is in place
            let userID : String = userID
            // To Book Now controller
            let navCtrl = tabBarCtrller.viewControllers![0] as! UINavigationController
            let bknctrl = navCtrl.topViewController as! BookNowScreen01
            // To By Date controller
            let navCtrl02 = tabBarCtrller.viewControllers![1] as! UINavigationController
            let bdctrl = navCtrl02.topViewController as! DateDurationScreen01
            // To By Room controller
            let navCtrl03 = tabBarCtrller.viewControllers![2] as! UINavigationController
            let brctrl = navCtrl03.topViewController as! RoomScreen01
            // To View Bookings controller
            let navCtrl04 = tabBarCtrller.viewControllers![3] as! UINavigationController
            let vbctrl = navCtrl04.topViewController as! ViewBookings

            bknctrl.userIDfromLogin = userID
            bdctrl.userIDfromLogin = userID
            brctrl.userIDfromLogin = userID
            vbctrl.userIDfromLogin = userID
        }

        outUsername.text = ""
        outPassword.text = ""
    }