skip to Main Content

Basically in the AppDelegate method of my app I connect to Firebase. I then need to initialize my UserProfileService before the app launches. Inside UserProfileService init I connect to Firebase to get the authenticated user data and store it.

The problem arises because if I don’t initialize UserProfileService before the app launches, as you can see in the code below, when I run the function .hasData() to check if the UserProfileService has inside it the data I need, it should either end up in the phoneRegistrationView or the mainTabBarView. If the user is indeed already authenticated, at app launch, since the initialization of UserProfileService needs to wait for Firebase to retrieve the data, the function .hasData() returns false and shows phoneRegistrationView() for a few milliseconds, then it returns to true and goes to mainTabBarView.

@main
struct myApp: App {
    @StateObject private var userProfileService = UserProfileService()
    var body: some Scene {
        WindowGroup {
        // user not registered or authenticated
        if !userProfileService.hasData() {
            NavigationView {
                phoneRegistrationView()
            }
            .environmentObject(userProfileService)
        }
        // user registered and profile completed
        else {
            mainTabBarView()
            .environmentObject(userProfileService)
        }
    }
}

Is there any way to solve this?

I tried await functions to initialize the data in UserProfileService but nothing seemed to work.

2

Answers


  1. The

    @main
    struct myApp: App {
    

    is an entry point to the app. Nothing should or will run before that. So you need to change your requirements and show some progress / loading screen while the data is being loaded:

            if userProfileService.isLoading {
                ProgressView {
                    Text("Please wait...")
                }
            } else if !userProfileService.hasData() {
            // ... same as before
    

    While you could set userProfileService.isLoading to true in the init of the UserProfileService, and set it back to false when you get a response from Firabase.

    This is of course the most primitive way, just to show the state. Many other ways are possible, but the point is: if you depend on some network operation, have a state in your app that "entertains" the user while that operation completes.

    Login or Signup to reply.
  2. @StateObject is for when you need a reference type in an @State and both of these are for when you want a source of truth for view data tied to the lifetime of something on screen. I.e. created on appear and destroyed on disappear. Since you wouldn’t want your service to ever be destroyed @StateObject is not the right tool for the job.

    Some other options are to use a singleton, see PersistenceController.shared in an Xcode template with core data checked. Or you could use the @UIApplicationDelegateAdaptor that gives you a place you can create services and respond to the usual app lifecycle delegate events.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search