Представление SwiftUI не обновляется до изменения EnvironmentObject - PullRequest
0 голосов
/ 10 ноября 2019

Я создаю приложение SwiftUI, которое включает в себя Firebase, чтобы включить вход в учетную запись, очень просто, просто пользовательский интерфейс с полями пароля и электронной почты, а затем кнопку для отправки. Как только пользователь войдет в систему, я сохраню пользовательский объект firebase в EnvironmentObject, так что остальные виды будут иметь к нему доступ. Проблема с приложением в настоящее время заключается в том, что после входа пользователя в систему и сохранения пользовательских данных в EnvironmentObject представление должно обновиться до измененного состояния, чтобы отобразить другой экран, но, похоже, представление все еще думает, что EnvironmentObjectравно нулю. Разве представления не изменяются автоматически на обновления в EnvironmentObject, как это происходит для переменных состояния, возможно?

Я убедился, что EnvironmentObject настроен правильно и передан как в предварительный просмотр, так и в 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
    }

}

Как вы можете видеть в представлении, предполагается отображать поля входа в систему, когда пользователь не вошел в систему, и когда пользователь вошел в представление, должно отображаться другое представление. Это другое представление не отображается.

Ответы [ 2 ]

0 голосов
/ 15 ноября 2019

Попробуйте использовать свойство @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
    }

}

Это должно обновить ваше представление, когда были внесены изменения в объекте User, например, электронная почта или отображаемое имя, потому что они опубликованы. Надеюсь, это поможет, gl

0 голосов
/ 10 ноября 2019

Думаешь, ты смешиваешь ObservableObject с BindableObject? Попробуйте вместо этого:

@Published var session: User?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...