Переменная сеанса Firebase всегда равна нулю

#ios #swift #firebase #firebase-authentication #swiftui

#iOS #swift #firebase #firebase-аутентификация #swiftui

Вопрос:

Схема приложения проста: если переменная сеанса равна нулю, появляется экран входа в систему. Если пароль и логин успешно введены, мы создаем новую модель пользователя, и переменная сеанса перестает быть нулевой. Однако этого не происходит, в результате перед нами всегда появляется экран входа в систему, независимо от того, был ли вход в систему успешным или нет.

(Я получаю сообщение отладки при открытии приложения «Получил пользователя: <FIRUser: 0x600003c29b80>», что указывает на отсутствие проблем с аутентификацией)

contentView.swift:

 import SwiftUI

struct ContentView: View {
    @EnvironmentObject var session: SessionStore
    
    func getUser () {
          session.listen()
      }

    var body: some View {
        Group {
            if (session.session != nil) {
                Text("Hello user!")
              } else {
                SignInView()
              }
        }.onAppear(perform: getUser)
    }
}
  

SessionStore.swift:

 import SwiftUI
import Firebase
import Combine

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 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,
                    email: user.email
                    
                )
            } 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
        }
    }
}
  

SignInView.swift:

 import SwiftUI

struct SignInView : View {

    @State var email: String = ""
    @State var password: String = ""
    @State var loading = false
    @State var error = false

    @EnvironmentObject var session: SessionStore

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

    var body: some View {
        VStack {
            TextField("email address", text: $email)
            SecureField("password", text: $password)
            if (error) {
                Text("ahhh crap")
            }
            Button(action: signIn) {
                Text("Sign In")
            }
        }
    }
}
  

Ответ №1:

Чтобы свойство наблюдалось в представлении, вам нужно опубликовать его, а не использовать пользовательский издатель, например

 class SessionStore : ObservableObject {
    @Published var session: User? = nil    // << here !!

// ... other code
  

и лучше явно назначить опубликованное свойство в основной очереди, например

  DispatchQueue.main.async {
    self.session = User(
        uid: user.uid,
        displayName: user.displayName,
        email: user.email
    )
 }