Context: I am trying to use firebase authentication and firestore to get the user's data. The problem I am running into is that the views are presented before the data is completely fetched and that obviously causes the app to crash. That being said, I am utilizing the firebase authentication listener in my app delegate to ensure the user is authenticated before fetching the users' data (which is also done in the app delegate as shown below)
App delegate snippet
class AppDelegate: NSObject, UIApplicationDelegate {
var handle: AuthStateDidChangeListenerHandle?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
self.handle = Auth.auth().addStateDidChangeListener { (auth, user) in
if (user != nil){
print("UserAuthentication User authenticated in delegate")
DatabaseDelegate().getUserInfo(UID: user!.uid, withCompletionHandler: {
print("got user data")
})
} else {
print(" UserAuthentication User not authenticated in delegate")
try! Auth.auth().signOut()
}
}
return true
}
This is the database code I am querying and want to listen for when the data is finished loading:
class DatabaseDelegate: ObservableObject {
@Published var userDataLoaded = Bool()
func getUserInfo(UID: String, withCompletionHandler completionHandler: @escaping () -> Void) {
database.collection("Users").document(UID).getDocument { (document, error) in
if let document = document, document.exists {
let data = document.data()!
guard let UID = data["UUID"] as? String else { return }
guard let Name = data["Name"] as? String else { return }
guard let PhoneNumber = data["PhoneNumber"] as? String else { return }
guard let StripeID = data["StripeID"] as? String else { return }
self.userDataLoaded = true
UserData.append(User(UID: UID, Name: Name, PhoneNumber: PhoneNumber, StripeID: StripeID, PurchasedContent: ["TEMP": true]))
completionHandler()
}
}
}
}
And this is the SwiftUI view I want to update based on the userDataLoaded above:
struct MainViewDelegate: View {
//MARK: VARIABLES
@State var showAnimation = true
@State var locationHandler = LocationHandler()
@ObservedObject var databaseDelegate = DatabaseDelegate()
init(){
//Check and enable user location
locationHandler.requestAuthorisation()
}
var body: some View {
VStack {
//Check if data has finished loading, if not, show loading. Listen for changes when the data is finished loading and then present the tab view when it is.
switch databaseDelegate.userDataLoaded {
case true:
TabView {
HomeView()
.tabItem {
Label("Home", systemImage: "house")
}
CheckoutView()
.tabItem {
Label("Services", systemImage: "bag")
}
SettingsView()
.tabItem {
Label("Settings", systemImage: "gearshape")
}
}
case false:
Text("Loading data")
}
}
}
}
Thank you in advanced. I am new to swiftui (transitioning from uikit) and I've spent too much time trying to solve this silly issue