Как загрузить пользовательские данные из Firestore и обновить свое представление после асинхронной аутентификации в Swift?

Я ищу способ получить пользователя из моей базы данных Firestore ПОСЛЕ завершения аутентификации и получения UID для пользователя, но ДО того, как мое представление загрузится на SwiftUI/Swift 5+. Или, альтернативно, я могу использовать ProgressView между ними.

В моем представлении ContentView у меня есть условное предложение о том, зарегистрирован ли пользователь или нет. Это поле в моем документе пользователя в Firebase, к которому мне нужен доступ.

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

Вот мое решение прямо сейчас:

Я создал класс SessionStore для обработки входов в систему с помощью Firebase:

class SessionStore : ObservableObject {
  u/Published var session: SessionUser? { didset { self.didChange.send(self) } }
  var handle: AuthStateDidChangeListenerHandle?

  // Auth listening by running addStateDidChangeListener
  func listen() { ... }

  // Unbind the Auth listener
  func unbind() { ... }

  func handleGoogleLogin() {
    GIDSignIn.sharedInstance.signIn(withPresenting: getRootViewController()) {
              signInResult, err in
    ...
    
      signInResult.user.refreshTokensIfNeeded { user, error in
      ...

        Auth.auth().signIn(with: credential) { result, err in
          print("success!")
          // TODO: run fetch user here somehow
        }
      }
    }
  }
}

Затем в моем объекте SessionUser у меня есть вызов для получения данных из коллекции в Firestore:

class SessionUser : ObservableObject {
  @Published var user: User?
  @Published var isUserOnboarded: Bool
  var uid: String
  
  init(uid) { ... }

  func fetchSessionUser() async {
    do {
      // Tries to get user from the datastore first in case user exists already
      if doesUserExist() {
        // Get user from Firestore db
        let doc = try await db.collection("users").document("\(userId)")
        if doc.exists {
          self.user = try document.data(as: User.self)
          self.isUserOnboarded = self.user.isUserOnboarded
        }
      } else {
        // Create user
      }
    }
  }
}

Для потомков, вот представление ContentView:

struct ContentView: View {
  @StateObject var session: SessionStore = SessionStore()

  var body: some View {
    VStack {
      if session.session != nil || Auth.auth().currentUser != nil {
        if session.session?.isUserOnboarded {
          MainView()
        } else {
          OnboardingView()
        }
      } else {
        StartPageView()
      }
   }
}

Я пробовал много вещей, таких как экранирование объекта в вызове выборки, создание инкапсулированного класса с опубликованной переменной для isUserOnboarded (как показано выше) и экспериментирование с вызовами DispatchQueue.main.async, но ничего не помогло. до сих пор.

Предыдущие ответы на StackOverflow/online показывают, что процедура аутентификации для Firebase является асинхронной (но, я думаю, это уже не так), и она не позволяет мне вызывать ее с ожиданием.

Вы должны использовать прослушиватель состояния аутентификации, чтобы один компонент знал, когда аутентификация завершается в другом компоненте.

Doug Stevenson 19.08.2024 03:26
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я ищу способ получить пользователя из моей базы данных Firestore ПОСЛЕ завершения аутентификации.

Это правда, что вы можете получить пользовательский объект Fireabsae, когда процесс аутентификации пройдет успешно, а затем использовать его дальше в своем коде, но это не решает всю проблему, а только половину. А как насчет выхода пользователя?

Поэтому, если вы хотите отслеживать состояние аутентификации пользователя и предпринимать соответствующие действия, я рекомендую вам использовать прослушиватель состояния аутентификации . Таким образом, вы сможете отслеживать состояние аутентификации в различных компонентах или во всем приложении.

Я получил вход и выход на работу. В моем SessionStore есть переменная handle для моего AuthStateDidChangeListenerHandle, и я прикрепил ее к моему ContentView onAppear. Для меня это ничего не меняет, но вход и выход работают как положено. Я пытаюсь выполнить второй вызов, чтобы получить свой флаг пользователя в коллекциях Firestore. Возможно, я неправильно понимаю, как полностью использовать прослушиватель состояния аутентификации.

Dilber 19.08.2024 21:00

Приятно слышать, что у вас заработал вход и выход. Прослушиватель состояния аутентификации никоим образом не связан с Firestore. Таким образом, вам придется действовать только тогда, когда состояние аутентификации пользователя изменится.

Alex Mamo 20.08.2024 05:52

Так мой ответ/комментарий помог? Могу ли я помочь вам с другой информацией?

Alex Mamo 20.08.2024 05:52

Это помогло понять прослушиватель состояния аутентификации, но я нашел другое решение, которое потребовало от меня переключить метод, который я использовал для получения пользователя, И изменить свой ObservableObject на использование @Observable макроса. Я перечислил решение в другом ответе!

Dilber 20.08.2024 11:17

Я видел ваш ответ, но состояние аутентификации не имеет ничего общего с тем, как вы читаете данные из Firestore: либо с помощью get(), либо с прослушиванием обновлений в реальном времени.

Alex Mamo 20.08.2024 13:06
Ответ принят как подходящий

В итоге я переключился на прослушиватель снимков , чтобы избежать вызова await, а затем также изменил свой SessionUser, чтобы он имел макрос @Observable вместо наследования ObservableObject, поскольку были проблемы с вложенными классами, которые не обновляли представление с моими @Published переменными. .

Прослушиватель снимков не имеет ничего общего с аутентификацией, он просто помогает прослушивать обновления в реальном времени в Firestore.

Alex Mamo 20.08.2024 13:05

Другие вопросы по теме