如何从 Firebase 检索数据,将其设置为全局变量,然后将其传递给下一个视图控制器?
How to retrieve data from Firebase, set it to a global variable, then pass it to the next view controller?
首先,这个问题是关于 iOS,而不是 android。希望它不会再次被标记为与 android 重复。
其次,为了解释清楚,这些是我对应用程序的意图 运行:
- 在 "shouldPerformSegueWithIdentifier"
内部执行检查
- 检查用户名和密码是否为空。如果为空,return false 并显示 alert
注意:我可以做到第 2 点。我知道如何从 firebase 检索数据。问题出在第3点之后。
- 否则,继续并比较 firebase 中的数据
- 如果找到匹配项,获取文档 ID 并将其设置为全局变量和 return TRUE,以便 prepareForSegue 方法能够 运行.
- 否则,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 true从 firebase 检索数据。
所以您需要做的是使用 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 = ""
}
首先,这个问题是关于 iOS,而不是 android。希望它不会再次被标记为与 android 重复。
其次,为了解释清楚,这些是我对应用程序的意图 运行:
- 在 "shouldPerformSegueWithIdentifier" 内部执行检查
- 检查用户名和密码是否为空。如果为空,return false 并显示 alert
注意:我可以做到第 2 点。我知道如何从 firebase 检索数据。问题出在第3点之后。
- 否则,继续并比较 firebase 中的数据
- 如果找到匹配项,获取文档 ID 并将其设置为全局变量和 return TRUE,以便 prepareForSegue 方法能够 运行.
- 否则,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 true从 firebase 检索数据。
所以您需要做的是使用 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 = ""
}