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



首先,这个问题是关于iOS,而不是Android。希望它不会再次被标记为复制到安卓机器人。

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

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

注意:我能够做到第2点。我知道如何从火力基地检索数据。问题出在第3点以后。

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

问题所在

我为堆栈溢出的解决方案做了很多研究,我了解它与代码 OUT 首先运行的异步相关的东西。但是,我找不到与应该执行Segue方法相关的单一解决方案。

不过,我尝试了 completionHandler 方法。但是,该代码段不能在该方法中返回 true 或 false,反过来,无法确定是否应执行 segue。此外,只有在我需要将该 userID 传递给其他视图控制器时,才能在该方法中检索数据。

这是 shouldPerformSegueWithIdentifier 代码(如果格式关闭,请原谅我,因为我通常不会在堆栈溢出中提问,但我无能为力,因为这让我很恼火,因为我在一整天梳理堆栈溢出后找不到解决方案。不过不要介意"return 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
}
}

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

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

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

和你的下一个家视图控制器,你可以回来,比如

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

方法2:Segue

将接收值设置为登录视图控制器的全局变量,并在执行Segue中使用它。

调用您的 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
}
}
}

希望,它有帮助..

堆栈溢出总是有用的

else检查中的问题是:

您执行的是异步任务,因此当您进行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,"")
}
}
}
}
}

因此,经过无数天的尝试,终于能够使其正常工作,尽管加载速度有点慢,但现在就可以了,因为它只是一个示例原型应用程序。如果你们中的任何人在从 Firebase 检索后遇到空填充,并且需要将该数据传递给另一个控制器,以下是我的做法:

从按钮代码获取的 IBAc:

@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 = ""
}

最新更新