Я ищу способ получить пользователя из моей базы данных 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 является асинхронной (но, я думаю, это уже не так), и она не позволяет мне вызывать ее с ожиданием.
Я ищу способ получить пользователя из моей базы данных Firestore ПОСЛЕ завершения аутентификации.
Это правда, что вы можете получить пользовательский объект Fireabsae, когда процесс аутентификации пройдет успешно, а затем использовать его дальше в своем коде, но это не решает всю проблему, а только половину. А как насчет выхода пользователя?
Поэтому, если вы хотите отслеживать состояние аутентификации пользователя и предпринимать соответствующие действия, я рекомендую вам использовать прослушиватель состояния аутентификации . Таким образом, вы сможете отслеживать состояние аутентификации в различных компонентах или во всем приложении.
Я получил вход и выход на работу. В моем SessionStore есть переменная handle
для моего AuthStateDidChangeListenerHandle
, и я прикрепил ее к моему ContentView onAppear
. Для меня это ничего не меняет, но вход и выход работают как положено. Я пытаюсь выполнить второй вызов, чтобы получить свой флаг пользователя в коллекциях Firestore. Возможно, я неправильно понимаю, как полностью использовать прослушиватель состояния аутентификации.
Приятно слышать, что у вас заработал вход и выход. Прослушиватель состояния аутентификации никоим образом не связан с Firestore. Таким образом, вам придется действовать только тогда, когда состояние аутентификации пользователя изменится.
Так мой ответ/комментарий помог? Могу ли я помочь вам с другой информацией?
Это помогло понять прослушиватель состояния аутентификации, но я нашел другое решение, которое потребовало от меня переключить метод, который я использовал для получения пользователя, И изменить свой ObservableObject
на использование @Observable
макроса. Я перечислил решение в другом ответе!
Я видел ваш ответ, но состояние аутентификации не имеет ничего общего с тем, как вы читаете данные из Firestore: либо с помощью get()
, либо с прослушиванием обновлений в реальном времени.
В итоге я переключился на прослушиватель снимков , чтобы избежать вызова await, а затем также изменил свой SessionUser, чтобы он имел макрос @Observable
вместо наследования ObservableObject
, поскольку были проблемы с вложенными классами, которые не обновляли представление с моими @Published
переменными. .
Прослушиватель снимков не имеет ничего общего с аутентификацией, он просто помогает прослушивать обновления в реальном времени в Firestore.
Вы должны использовать прослушиватель состояния аутентификации, чтобы один компонент знал, когда аутентификация завершается в другом компоненте.