如何使用 Firestore 数据同步更新 UILabel?

How do I update UILabels synchronously with Firestore data?

我目前正在构建一个 iOS 应用程序,它将同步来自 Firestore 的帐户信息。我已连接并运行 login/register 进程。但是,我需要帮助了解如何在用户登录 in/out 时自动更新 MenuVC 中的 logInOutBtnfullNameTxtemailTxt。目前,它会在我关闭然后重新打开菜单时更新,但是我应该使用什么来自动更新它而不必关闭菜单?谢谢!

// 菜单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)