【问题标题】:How do I update UILabels synchronously with Firestore data?如何与 Firestore 数据同步更新 UILabel?
【发布时间】:2020-04-16 22:30:19
【问题描述】:

我目前正在构建一个 iOS 应用程序,它将从 Firestore 同步帐户信息。我已经连接并工作了登录/注册过程。但是,我需要帮助了解如何在用户登录/注销时自动更新我的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
    }

}

// 我的应用菜单

【问题讨论】:

  • 您可以创建一个函数,当按下按钮时,它会运行一个登录/退出函数来设置值,并设置 UI
  • 或者你可以观察授权状态(例如Auth.auth().addStateDidChangeListener { ... })。
  • @Evan,我在问题中添加了登录/退出功能
  • presentLoginControllerFunction() 中的内容,因为您可能需要替换它,然后在按钮按下函数中运行代码
  • @Evan 我为你添加了我的 presentLoginController 函数

标签: swift firebase google-cloud-firestore swrevealviewcontroller


【解决方案1】:

注销过程非常简单,并且被标记为 throws,因此如果失败,它将生成一个可以由 catch 处理的错误。它不是异步的,因此不会有(或不需要)闭包。

简单来说

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 并让它对用户登录/退出做出反应

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) 

【讨论】:

  • 我可以把我的回购发给你吗,@Jay?我的LoginVC 中有我所有的登录代码,所以我需要你看看我如何更新我的MenuVC 的用户界面
  • 你拯救了杰伊!!!我只需要将 Auth.auth().addAuthStateDidChangeListener { ... } 放入我的 viewWillAppear
猜你喜欢
  • 1970-01-01
  • 2021-01-03
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
  • 2021-05-19
  • 1970-01-01
  • 2022-01-18
  • 2019-07-12
相关资源
最近更新 更多