gpt4 book ai didi

ios - SwiftUI View 未更新为 EnvironmentObject 更改

转载 作者:行者123 更新时间:2023-11-28 20:50:37 24 4
gpt4 key购买 nike

我正在创建一个包含 Firebase 的 SwiftUI 应用程序以启用登录帐户,非常简单,只需一个带有密码和电子邮件字段的 ui 表单,然后是一个提交按钮。用户登录后,我将 firebase 用户对象存储在 EnvironmentObject 中,以便其余 View 可以访问它。该应用程序目前的问题是,一旦用户登录并且用户数据存储在 EnvironmentObject 中, View 应该更新到此状态的更改以显示不同的屏幕,但 View 似乎仍然认为 EnvironmentObject等于零。 View 是否不会像它们对状态变量所做的那样自动更改为 EnvironmentObject 中的更新?

我已确保 EnvironmentObject 已正确设置并传递给预览和 SceneDelegate

通过在登录时将帐户信息打印到控制台,确保应用程序确实成功登录用户,但 View 本身只会显示 nil 帐户信息,似乎它不会使用用户信息访问更新的 EnvironmentObject .

import SwiftUI
import Firebase
import Combine

struct ContentView: View {

@EnvironmentObject var session: SessionStore

@State var emailTextField: String = ""
@State var passwordTextField: String = ""

@State var loading = false
@State var error = false

var body: some View {
VStack {
if (session.session != nil) {
Home()
} else {
Form {
TextField("Email", text: $emailTextField)
SecureField("Password", text: $passwordTextField)
Button(action: signIn) {
Text("Sign in")
}
}

Text("Session: \(session.session?.email ?? "no user")")
}
}.onAppear(perform: getUser)
}

func getUser () {
session.listen()
}

func signIn () {
loading = true
error = false
session.signIn(email: emailTextField, password: passwordTextField) { (result, error) in
self.loading = false
if error != nil {
self.error = true
} else {
self.emailTextField = ""
self.passwordTextField = ""
}
}
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(SessionStore())
}
}



class SessionStore : ObservableObject {

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 account = user {
// if we have a user, create a new user model
print("Got user: \(account)")
self.session = User(
uid: account.uid,
displayName: account.displayName,
email: account.email
)
print("Session: \(self.session?.email ?? "no user")")
} else {
// if we don't have a user, set our session to nil
self.session = nil
}
}
}

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
}
}

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

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
}

}

如您在 View 中所见,它应该在用户未登录时呈现登录字段,而当用户登录时 View 应显示另一个 View 。其他 View 未显示。

最佳答案

尝试使用@Published 属性。尝试实现这样的东西:

class SessionStore : ObservableObject {
@Published var session: User
}

class User: ObservableObject {
@Published var uid: String
@Published var email: String?
@Published var displayName: String?

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

}

这应该会在用户对象发生更改时更新您的 View ,例如电子邮件或显示名称,因为它们已发布。希望这会有所帮助,gl

更新:

因为 SwiftUI 还不支持嵌套的 Observables,所以你需要自己通知你的主模型。

查看此片段如何在 ObservableObject 中使用嵌套的 ObservableObject:

class Submodel1: ObservableObject {
@Published var count = 0
}

class Submodel2: ObservableObject {
@Published var count = 0
}

class Model: ObservableObject {
@Published var submodel1: Submodel1 = Submodel1()
@Published var submodel2: Submodel2 = Submodel2()

var anyCancellable: AnyCancellable? = nil
var anyCancellable2: AnyCancellable? = nil

init() {

anyCancellable = submodel1.objectWillChange.sink { (_) in
self.objectWillChange.send()
}

anyCancellable2 = submodel2.objectWillChange.sink { (_) in
self.objectWillChange.send()
}
}
}

当子模型中的数据发生变化时,主模型会通知自己。这将导致 View 更新。

关于ios - SwiftUI View 未更新为 EnvironmentObject 更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58784475/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com