ios - 用户在 Firebase 上使用 Google 登录后,如何在 swiftUI 中重新呈现我的 View ?

标签 ios swift firebase authentication swiftui

我对 iOS 编程尤其是 swiftUI 还很陌生。 我有一个问题,我试图在我的应用程序中集成 firebase auth 以管理用户。 现在登录和注销基本上可以正常工作了,问题是,登录后,我的 View (有条件地呈现 Google 登录按钮或内容列表不会重新呈现,所以我仍然看到登录按钮,甚至尽管我已登录)。

我已经设置了一个可观察对象来保存我的身份验证状态,但不幸的是,它不会自动重新加载当前用户。所以我设置了一个函数来手动重新加载它,我想在登录时触发它。这适用于注销按钮,但登录在 AppDelegate 中完成,由于某种原因我无法访问 reloadUser() 函数。

我相信有更好的方法可以做到这一点,如果有任何帮助,我将不胜感激!

环境:

final class UserData: ObservableObject {
    @Published var showFavoritesOnly = false
    @Published var qrTags = qrTagData
    @Published var user: User? = Auth.auth().currentUser

    func reloadUser() -> Void {
        self.user = Auth.auth().currentUser
    }
}

我要渲染的 View :

struct MyQuaggsList: View {
        @EnvironmentObject private var userData: UserData

        var body: some View {
            Group {
                if getLogInState() != nil {
                    VStack {
                        NavigationView {
                            List {
                                Toggle(isOn: $userData.showFavoritesOnly) {
                                    Text("Show Favorites Only")
                                }

                                ForEach(userData.qrTags) { qrTag in
                                    if !self.userData.showFavoritesOnly || qrTag.isFavorite {
                                        NavigationLink(
                                            destination: QuagDetail(qrTag: qrTag)
                                                .environmentObject(self.userData)
                                        ) {
                                            QuaggRow(qrTag: qrTag)
                                        }
                                    }
                                }
                            }
                            .navigationBarTitle(Text("My Quaggs"))
                        }
                        SignOutButton()
                    }
                } else {
                    SignInView()
                }
            }.onAppear(perform: {self.userData.reloadUser()})
        }

        func getLogInState() -> User? {
            return Auth.auth().currentUser
        }
    }

另外,请注意 .onAppear() 函数,不幸的是,该函数仅在初始出现时触发,而不是在用户登录后重新出现 View 时触发。

提前致谢!这真的很令人沮丧。

最佳答案

firebase 和 swiftUI 组合起初有点棘手,但您会发现每个项目都使用相同的模式,不用担心。 只需按照我的步骤定制您的项目,这是我们的策略。

- 这可能是一个很长的答案,但我想将其作为所有在 Stack OverFlow 中管理的 Firebase-SwiftUI 用户的引用。 -

  1. 创建一个提供 BindableObject 的 SessionStore 类,并听取您的用户身份验证并处理 Auth 和 CRUD 方法。
  2. 为我们的项目创建模型(您已经这样做了)
  3. 在 SessionStore 类中添加 Auth 方法。
  4. 倾听变化并将事物整合在一起。

让我们从 SessionStore 类开始: 导入 SwiftUI 导入 Firebase 导入组合

class SessionStore : BindableObject {
    var didChange = PassthroughSubject<SessionStore, Never>()
    var session: User? { didSet { self.didChange.send(self) }}
    var handle: AuthStateDidChangeListenerHandle?

    func listen () {
        // monitor authentication changes using firebase
        handle = Auth.auth().addStateDidChangeListener { (auth, user) in
            if let user = user {
                // if we have a user, create a new user model
                print("Got user: \(user)")
                self.session = User(
                    uid: user.uid,
                    displayName: user.displayName
                )
            } else {
                // if we don't have a user, set our session to nil
                self.session = nil
            }
        }
    }

    // additional methods (sign up, sign in) will go here
}

请注意,我们已经声明我们的 session 属性是一个可选的 User 类型,我们还没有定义它。让我们快速制作一个:

class User {
    var uid: String
    var email: String?
    var displayName: String?

    init(uid: String, displayName: String?, email: String?) {
        self.uid = uid
        self.email = email
        self.displayName = displayName
    }

}

现在,添加signUpsignInsignOut/strong>方法

class SessionStore : BindableObject {

    // prev code...

    func signUp(
        email: String,
        password: String,
        handler: @escaping AuthDataResultCallback
        ) {
        Auth.auth().createUser(withEmail: email, password: password, completion: handler)
    }

    func signIn(
        email: String,
        password: String,
        handler: @escaping AuthDataResultCallback
        ) {
        Auth.auth().signIn(withEmail: email, password: password, completion: handler)
    }

    func signOut () -> Bool {
        do {
            try Auth.auth().signOut()
            self.session = nil
            return true
        } catch {
            return false
        }
    }
}

最后,我们需要一种方法来停止监听我们的身份验证更改处理程序。

class SessionStore : BindableObject {

    // prev code...

    func unbind () {
        if let handle = handle {
            Auth.auth().removeStateDidChangeListener(handle)
        }
    }
}

最后,制作我们的内容 View :

import SwiftUI

struct ContentView : View {

  @EnvironmentObject var session: SessionStore
  var body: some View {
    Group { 
     if (session.session != nil) {  
      Text("Hello user!") 
     } else {
        Text("Our authentication screen goes here...")   
    }  
   }
  }
}

关于ios - 用户在 Firebase 上使用 Google 登录后,如何在 swiftUI 中重新呈现我的 View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62083056/

相关文章:

iphone - 将 UIView 添加到另一个是否安全,以便 subview 的框架比父 View 的框架大得多

iOS 在 UILabel 上将时间显示为分数和高分

ios - child 因扇出而改变

iOS 7 视网膜和普通图像命名约定

java - 可以从 onChildChanged 获取旧数据吗? ( java )

Swift firebase 搜索落后一次重新加载

swift - 创建从多个协议(protocol)继承的协议(protocol)类型的对象时出错

ios - 如何在 swift 中使用 header 完成 api 调用

json - 使用 Swift 从 AFNetworking 访问 JSON 数据

java - 如何检查我的 Firebase 数据库是否包含特定用户的数据? (安卓/ java )