如何使用 Firestore 数据同步更新 UILabel?
How do I update UILabels synchronously with Firestore data?
我目前正在构建一个 iOS 应用程序,它将同步来自 Firestore 的帐户信息。我已连接并运行 login/register 进程。但是,我需要帮助了解如何在用户登录 in/out 时自动更新 MenuVC
中的 logInOutBtn
、fullNameTxt
和 emailTxt
。目前,它会在我关闭然后重新打开菜单时更新,但是我应该使用什么来自动更新它而不必关闭菜单?谢谢!
// 菜单VC
override func viewDidAppear(_ animated: Bool) {
if let user = Auth.auth().currentUser , !user.isAnonymous {
// We are logged in
logInOutBtn.setTitle("Logout", for: .normal)
if UserService.userListener == nil {
UserService.getCurrentUser {
self.fullNameTxt.text = UserService.user.fullName
self.emailTxt.text = UserService.user.email
}
}
} else {
logInOutBtn.setTitle("Login", for: .normal)
self.fullNameTxt.text = "Sign in or create an account"
self.emailTxt.text = "to continue."
}
}
fileprivate func presentLoginController() {
let storyboard = UIStoryboard(name: Storyboard.LoginStoryboard, bundle: nil)
if #available(iOS 13.0, *) {
let controller = storyboard.instantiateViewController(identifier: StoryboardId.LoginVC)
present(controller, animated: true, completion: nil)
} else {
// Fallback on earlier versions
}
}
@IBAction func logInOutClicked(_ sender: Any) {
guard let user = Auth.auth().currentUser else { return }
if user.isAnonymous {
presentLoginController()
} else {
do {
try Auth.auth().signOut()
UserService.logoutUser()
Auth.auth().signInAnonymously { (result, error) in
if let error = error {
debugPrint(error)
Auth.auth().handleFireAuthError(error: error, vc: self)
}
self.presentLoginController()
}
} catch {
debugPrint(error)
Auth.auth().handleFireAuthError(error: error, vc: self)
}
}
}
// 用户服务
func getCurrentUser(completion: @escaping () -> ()) {
guard let authUser = auth.currentUser else { return }
let userRef = db.collection("users").document(authUser.uid)
userListener = userRef.addSnapshotListener({ (snap, error) in
if let error = error {
debugPrint(error.localizedDescription)
return
}
guard let data = snap?.data() else { return }
self.user = User.init(data: data)
completion()
})
// 用户模型
struct User {
var fullName: String
var address: String
var id: String
var email: String
var stripeId: String
init(fullName: String = "",
address: String = "",
id: String = "",
email: String = "",
stripeId: String = "") {
self.fullName = fullName
self.address = address
self.id = id
self.email = email
self.stripeId = stripeId
}
init(data: [String : Any]) {
fullName = data["fullName"] as? String ?? ""
address = data["address"] as? String ?? ""
id = data["id"] as? String ?? ""
email = data["email"] as? String ?? ""
stripeId = data["stripeId"] as? String ?? ""
}
static func modelToData(user: User) -> [String : Any] {
let data : [String : Any] = [
"fullName" : user.fullName,
"address" : user.address,
"id" : user.id,
"email" : user.email,
"stripeId" : user.stripeId
]
return data
}
}
// 我的应用程序菜单
注销过程非常简单,并被标记为抛出,因此如果失败,它将生成一个错误,该错误可由捕获处理。它不是异步的,所以它不会(或不需要)闭包。
这么简单地说
func signOut() {
let firebaseAuth = Auth.auth()
do {
try firebaseAuth.signOut()
print("successful signout")
self.logInOutBtn.setTitle("Log In", for: .normal)
self.fullNameTxt.text = ""
self.emailTxt.text = ""
} catch let signOutError as NSError {
print ("Error signing out: %@", signOutError)
//present the error to the user/handle the error
}
}
signIn 函数 是 与闭包异步的,因此当用户成功登录时,闭包中的代码将触发,这是更新 UI.
Auth.auth().signIn(withEmail: email, password: password) { [weak self] authResult, error in
guard let strongSelf = self else { return }
// update the UI here.
}
你也可以只用观察者监控 authState 并让它对用户登录做出反应 in/out
self.authListener = Auth.auth()?.addAuthStateDidChangeListener { auth, user in
if let theUser = user {
print("User logged in \(theUser)") // User is signed in.
self.dismissViewControllerAnimated(true, completion: nil)
} else {
print("Need to login.") // No user is signed in.
//present login view controller
}
}
如果您不想再观察授权状态,可以使用
将其删除
Auth.auth()?.removeAuthStateDidChangeListener(self.authListener)
我目前正在构建一个 iOS 应用程序,它将同步来自 Firestore 的帐户信息。我已连接并运行 login/register 进程。但是,我需要帮助了解如何在用户登录 in/out 时自动更新 MenuVC
中的 logInOutBtn
、fullNameTxt
和 emailTxt
。目前,它会在我关闭然后重新打开菜单时更新,但是我应该使用什么来自动更新它而不必关闭菜单?谢谢!
// 菜单VC
override func viewDidAppear(_ animated: Bool) {
if let user = Auth.auth().currentUser , !user.isAnonymous {
// We are logged in
logInOutBtn.setTitle("Logout", for: .normal)
if UserService.userListener == nil {
UserService.getCurrentUser {
self.fullNameTxt.text = UserService.user.fullName
self.emailTxt.text = UserService.user.email
}
}
} else {
logInOutBtn.setTitle("Login", for: .normal)
self.fullNameTxt.text = "Sign in or create an account"
self.emailTxt.text = "to continue."
}
}
fileprivate func presentLoginController() {
let storyboard = UIStoryboard(name: Storyboard.LoginStoryboard, bundle: nil)
if #available(iOS 13.0, *) {
let controller = storyboard.instantiateViewController(identifier: StoryboardId.LoginVC)
present(controller, animated: true, completion: nil)
} else {
// Fallback on earlier versions
}
}
@IBAction func logInOutClicked(_ sender: Any) {
guard let user = Auth.auth().currentUser else { return }
if user.isAnonymous {
presentLoginController()
} else {
do {
try Auth.auth().signOut()
UserService.logoutUser()
Auth.auth().signInAnonymously { (result, error) in
if let error = error {
debugPrint(error)
Auth.auth().handleFireAuthError(error: error, vc: self)
}
self.presentLoginController()
}
} catch {
debugPrint(error)
Auth.auth().handleFireAuthError(error: error, vc: self)
}
}
}
// 用户服务
func getCurrentUser(completion: @escaping () -> ()) {
guard let authUser = auth.currentUser else { return }
let userRef = db.collection("users").document(authUser.uid)
userListener = userRef.addSnapshotListener({ (snap, error) in
if let error = error {
debugPrint(error.localizedDescription)
return
}
guard let data = snap?.data() else { return }
self.user = User.init(data: data)
completion()
})
// 用户模型
struct User {
var fullName: String
var address: String
var id: String
var email: String
var stripeId: String
init(fullName: String = "",
address: String = "",
id: String = "",
email: String = "",
stripeId: String = "") {
self.fullName = fullName
self.address = address
self.id = id
self.email = email
self.stripeId = stripeId
}
init(data: [String : Any]) {
fullName = data["fullName"] as? String ?? ""
address = data["address"] as? String ?? ""
id = data["id"] as? String ?? ""
email = data["email"] as? String ?? ""
stripeId = data["stripeId"] as? String ?? ""
}
static func modelToData(user: User) -> [String : Any] {
let data : [String : Any] = [
"fullName" : user.fullName,
"address" : user.address,
"id" : user.id,
"email" : user.email,
"stripeId" : user.stripeId
]
return data
}
}
// 我的应用程序菜单
注销过程非常简单,并被标记为抛出,因此如果失败,它将生成一个错误,该错误可由捕获处理。它不是异步的,所以它不会(或不需要)闭包。
这么简单地说
func signOut() {
let firebaseAuth = Auth.auth()
do {
try firebaseAuth.signOut()
print("successful signout")
self.logInOutBtn.setTitle("Log In", for: .normal)
self.fullNameTxt.text = ""
self.emailTxt.text = ""
} catch let signOutError as NSError {
print ("Error signing out: %@", signOutError)
//present the error to the user/handle the error
}
}
signIn 函数 是 与闭包异步的,因此当用户成功登录时,闭包中的代码将触发,这是更新 UI.
Auth.auth().signIn(withEmail: email, password: password) { [weak self] authResult, error in
guard let strongSelf = self else { return }
// update the UI here.
}
你也可以只用观察者监控 authState 并让它对用户登录做出反应 in/out
self.authListener = Auth.auth()?.addAuthStateDidChangeListener { auth, user in
if let theUser = user {
print("User logged in \(theUser)") // User is signed in.
self.dismissViewControllerAnimated(true, completion: nil)
} else {
print("Need to login.") // No user is signed in.
//present login view controller
}
}
如果您不想再观察授权状态,可以使用
将其删除Auth.auth()?.removeAuthStateDidChangeListener(self.authListener)