Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios SwiftUI视图未更新为环境对象更改_Ios_Swift_Swiftui - Fatal编程技术网

Ios SwiftUI视图未更新为环境对象更改

Ios SwiftUI视图未更新为环境对象更改,ios,swift,swiftui,Ios,Swift,Swiftui,我正在创建一个包含Firebase的SwiftUI应用程序,可以登录到一个帐户,非常简单,只是一个带有密码和电子邮件字段的ui表单,然后是一个提交按钮。用户登录后,我将firebase用户对象存储在EnvironmentObject中,以便其他视图可以访问它。当前应用程序的问题是,一旦用户登录并将用户数据存储在EnvironmentObject中,视图应该更新为该应用程序的更改状态以显示不同的屏幕,但视图似乎仍然认为EnvironmentObject等于零。视图在EnvironmentObjec

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

我已确保正确设置了EnvironmentObject并将其传递给preview和SceneDelegate

登录时将帐户信息打印到控制台,确保应用程序确实成功登录到用户,但视图本身仅显示帐户信息为零,似乎它不会使用用户信息访问更新的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
    }

}
导入快捷界面
进口火基
进口联合收割机
结构ContentView:View{
@环境对象变量会话:会话存储
@状态变量emailTextField:String=“”
@状态变量passwordTextField:String=“”
@状态变量加载=false
@状态变量错误=false
var body:一些观点{
VStack{
如果(session.session!=nil){
Home()
}否则{
形式{
文本字段(“电子邮件”,文本:$emailTextField)
SecureField(“密码”,文本:$passwordTextField)
按钮(操作:登录){
文本(“登录”)
}
}
文本(“会话:\(会话.会话?.email??“无用户”))
}
}.onAppear(执行:getUser)
}
func getUser(){
听一听
}
函数签名(){
加载=真
错误=错误
session.signIn(电子邮件:emailTextField,密码:passwordTextField){(结果,错误)在
自加载=错误
如果错误!=nil{
self.error=true
}否则{
self.emailTextField=“”
self.passwordTextField=“”
}
}
}
}
结构内容视图\u预览:PreviewProvider{
静态var预览:一些视图{
ContentView().environmentObject(SessionStore())
}
}
类SessionStore:ObservableObject{
var didChange=PassthroughSubject()
var会话:用户?{didSet{self.didChange.send(self)}
变量句柄:AuthStateDidChangeListenerHandle?
func listen(){
//使用firebase监视身份验证更改
handle=Auth.Auth().addStateDidChangeListener{(Auth,user)在中
如果let account=user{
//如果我们有一个用户,创建一个新的用户模型
打印(“已获取用户:\(帐户)”)
self.session=用户(
uid:account.uid,
displayName:account.displayName,
电子邮件:account.email
)
打印(“会话:\(self.Session?.email??“无用户”))
}否则{
//如果没有用户,请将会话设置为nil
self.session=nil
}
}
}
func注册(
电子邮件:String,
密码:String,
处理程序:@正在转义的AuthDataResultCallback
) {
Auth.Auth().createUser(带电子邮件:电子邮件,密码:密码,完成:处理程序)
}
职能签名(
电子邮件:String,
密码:String,
处理程序:@正在转义的AuthDataResultCallback
) {
Auth.Auth().sign(使用电子邮件:电子邮件,密码:密码,完成:处理程序)
}
func签出()->Bool{
做{
请尝试Auth.Auth().signOut()
self.session=nil
返回真值
}抓住{
返回错误
}
}
func unbind(){
如果let handle=handle{
Auth.Auth().removeStateDidChangeListener(句柄)
}
}
}
类用户{
变量uid:String
var电子邮件:字符串?
var显示名称:字符串?
初始化(uid:String,displayName:String?,email:String?){
self.uid=uid
self.email=电子邮件
self.displayName=displayName
}
}

正如您在视图中看到的,它应该在用户未登录时呈现登录字段,并且当用户登录时,视图应该显示另一个视图。另一个视图未显示。

请尝试使用@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
    }

}
当用户对象(如电子邮件或显示名)发生更改时,这将更新您的视图,因为它们已发布。 希望这会有帮助,德国劳埃德船级社

更新:

因为SwiftUI还不支持嵌套的可观察对象,所以您需要自己通知主模型

请参阅以下代码片段,了解如何在ObserveObject中使用嵌套的ObserveObject:

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()
        }
    }
}
当子模型中的数据发生更改时,主模型将通知自己。这将导致视图上的更新


如果这对你有帮助,请告诉我。。祝你好运

如果您使用的是PassthroughSubject,那么var名称应该是
willChange
而不是
didChange
我遵循了完全相同的示例并提出了完全相同的问题,谢谢。