Обновление пользовательского интерфейса с помощью DispatchQueue в Firebase — SwiftUI

#google-cloud-firestore #swiftui #grand-central-dispatch #swift5

#google-cloud-firestore #swiftui #grand-central-dispatch #swift5

Вопрос:

Я пытаюсь использовать a DispatchQueue для обновления своего пользовательского интерфейса, поэтому, когда Firebase аутентифицирует пользователя, я могу передать вновь созданные данные на следующий экран.

У меня есть a SignUpView , который регистрирует пользователя, а затем переходит к a ProfileView в случае успеха. Это ProfileView позволяет пользователю добавлять более конкретные детали для приложения.

У меня есть userSession объект, который успешно регистрирует пользователя, но не сразу обновляет пользовательский интерфейс на следующем экране. Вероятно, это связано с тем, что я неправильно использую DispatchQueue.main.async , что я не могу использовать в теле View конструктора в SwiftUI.

Вот View я использую для заполнения имени пользователя в ProfileView том, что я получаю от SignUpView .

Примечание: Когда я перехожу к домашнему просмотру, появляется имя пользователя и другие жизненно важные данные. Я предполагаю, что это связано с тем, что в этот момент база данных обновляется, и я могу начать считывать значения.

 
struct VitalsHeaderView: View {
    @EnvironmentObject var session: SessionStore
    
    var body: some View {
        VStack {
            if session.isLoggedIn {
                Text(session.userSession!.username)
                    .font(.system(size: 20, weight: .bold))
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .foregroundColor(Color(#colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)))
            }
        }
        .padding(.top, 30)
        .padding(.leading, 30)
    }
}

  

Ниже вы видите плохой хак, который не работает, но это что-то вроде того, что я хочу сделать. Как я могу использовать очередь отправки для обновления пользовательского интерфейса?

 struct VitalsHeaderView: View {
    @EnvironmentObject var session: SessionStore
    @ObservedObject var signUpViewModel = SignUpViewModel()

    func updateUI() {
        DispatchQueue.main.asyncAfter(deadline: .now()   2) {
            self.session.isLoggedIn = true
        }
    }
    
    var body: some View {
        VStack {
            if session.isLoggedIn {
                Button(action: updateUI) {
                    Text(session.userSession!.username)
                        .font(.system(size: 20, weight: .bold))
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .foregroundColor(Color(#colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)))
                }
            }
        }
        .padding(.top, 30)
        .padding(.leading, 30)
    }
}

  

ОБНОВЛЕНО

Вот мой SessionStore код

 
import Foundation
import Combine
import Firebase

class SessionStore: ObservableObject {
    
    @Published var isLoggedIn: Bool = UserDefaults.standard.bool(forKey: "isLoggedIn") {
        didSet {
            UserDefaults.standard.set(self.isLoggedIn, forKey: "isLoggedIn")
        }
    }
    
    var userSession: User?
    
    var handle: AuthStateDidChangeListenerHandle?
    
    func listenAuthenticationState() {
        handle = Auth.auth().addStateDidChangeListener({ (auth, user) in
            if let user = user {
                print(user.email as Any)
                let firestoreUserId = Ref.FIRESTORE_DOCUMENT_USERID(userId: user.uid)
                firestoreUserId.getDocument { (document, error) in
                    if let dict = document?.data() {
                        guard let decodeUser = try? User.init(fromDictionary: dict) else { return }
                        DispatchQueue.main.async {
                           self.userSession = decodeUser
                           self.isLoggedIn = true
                        }
                    }
                }
            } else {
                self.isLoggedIn = false
                self.userSession = nil
            }
        })
    }
    
    func logout() {
        do {
            try Auth.auth().signOut()
        } catch  {
        }
    }
    
    func unbind() {
        if let handle = handle {
            Auth.auth().removeStateDidChangeListener(handle)
        }
    }
    
    deinit {
        unbind()
    }
}

  

Я инициализирую VitalsHeaderView в ProfileView , который является структурой выше VitalsHeaderView .

 
struct ProfileView: View {
    @EnvironmentObject var session: SessionStore
    
    @ObservedObject var profileViewModel = ProfileViewModel()
    @ObservedObject var signUpViewModel = SignUpViewModel()
    
    var body: some View {
        ZStack {
            Color(#colorLiteral(red: 0.9058823529, green: 0.9254901961, blue: 0.968627451, alpha: 1)).edgesIgnoringSafeArea(.all)
            ZStack(alignment: .top) {
                Color(#colorLiteral(red: 0.9058823529, green: 0.9254901961, blue: 0.968627451, alpha: 1))
                    .clipShape(RoundedRectangle(cornerRadius: 30, style: .continuous))
                    .edgesIgnoringSafeArea(.bottom)
                
                ScrollView(.vertical, showsIndicators: false) {
                    
                    VStack {
                        ProfileHeaderView(signUpViewModel: signUpViewModel)
                        
                        VitalsHeaderView(signUpViewModel: signUpViewModel)
      
                        ShareProfileView(profileViewModel: profileViewModel)
                    }
                    .padding(.top, 30)
                }
            }
        }
        .navigationBarHidden(true)
        .navigationBarTitle("")
    }
}

  

ПРИМЕЧАНИЕ: я только что добавил (и протестировал) добавление свойства signUpViewModel в представление заголовка Vitals и по-прежнему ничего

Комментарии:

1. Не могли бы вы также добавить свой код для хранилища сеансов и как вы инициализируете свой VitalsHeaderView ?

2. Вам нужно убедиться, что SessionStore это соответствует протоколу, а также isLoggedIn является @Published переменной.

3. @Zorayr готово. SessionStore соответствует ObservableObject . Это то, что вы подразумеваете под протоколом? Кроме того, isLoggedIn это действительно @Published свойство.