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

时间:2019-12-12 09:28:55

标签: ios swift google-cloud-firestore segue

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

第二,为了清楚解释,这些是我对应用程序运行方式的意图:

  1. 在“ shouldPerformSegueWithIdentifier”内部执行检查
  2. 检查空的用户名和密码。如果为空,则返回false并显示警报

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

  1. 否则,继续进行操作并比较Firebase中的数据
  2. 如果找到匹配项,请获取documentID并将其设置为全局变量,然后返回TRUE,以便prepareForSegue方法能够运行。
  3. 否则,返回FALSE并显示警报,提示没有匹配的凭据

问题

我对堆栈溢出的解决方案进行了很多研究,并且我了解它与异步有关,而异步代码首先将在其中运行。但是,我找不到与shouldPerformSegue方法相关的单个解决方案。

虽然我尝试了completionHandler方法。但是,该代码段无法在该方法内返回true或false,因此无法确定是否应该执行segue。另外,只有当我需要将该用户ID传递到其他视图控制器时,才能在该方法中检索数据。

这是shouldPerformSegueWithIdentifier代码(如果格式化已关闭,请原谅我,因为我通常不会在堆栈溢出中问问题,但是我无能为力,因为这很烦我,因为我找不到解决方案经过一整天的梳理堆栈溢出。尽管不要介意“返回true”,因为在此期间我仍然需要访问其他视图控制器,因此,除了空检查之外,我现在将其设置为true。) :

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
        }
    }

3 个答案:

答案 0 :(得分:0)

其他检查中的问题是:

您执行异步任务,因此,当您通过 else 检查时,会发生以下情况:在从 firebase 检索数据之前,您返回 true 。 >。

所以您需要做的是使用completionHandler或一些通知,然后将函数返回类型更改为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,"")
                }
            }
        }
    }
}

答案 1 :(得分:0)

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

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

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

和您可以返回的下一个homeViewController,例如

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

方法2: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
                    }
                }
    }

希望,它会有所帮助..

stackoverflow总是有用的

答案 2 :(得分:0)

因此,在尝试了无数天之后,终于能够使它正常工作,尽管加载速度有点慢,但是现在就可以了,因为它只是一个示例原型应用程序。如果您中的任何一个在从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 = ""
    }