在 StateObject 初始化之前在应用程序委托中进行 Firebase 初始化

Firebase initialisation in application delegate before StateObject initialisation

我正在用 SwiftUI 编写应用程序并使用 Firebase 作为我的后端。

我有一个工作首选项面板,它由应用程序本身内的一个模式组成,但我想利用 macOS 的一致首选项 window,其中包括菜单选项以及写在 this文章。

这是我的应用声明和委托。

@main
struct SchedulerApp: App {
    #if os(macOS)
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    #else
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    #endif
    
    @StateObject var authState = AuthState()
    @StateObject var model = Model()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .frame(minWidth: 800, minHeight: 450)
                .environmentObject(model)
                .environmentObject(authState)
            
        }
        .commands {
            SidebarCommands()
        }
        
        #if os(macOS)
        Settings {
            Preferences()
        }
        #endif
    }
}

#if os(macOS)
class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationWillFinishLaunching(_ notification: Notification) {
        FirebaseApp.configure()
    }
}
#else
class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        FirebaseApp.configure()
        
        
        
        return true
    }
}
#endif

您可以看到我有一个委托和一个状态对象,一个对象侦听身份验证状态,另一个对象保存用户数据和设置:

class AuthState: ObservableObject {
    var handle: AuthStateDidChangeListenerHandle?
    
    @Published var signedIn: Bool? = nil
    
    init() {
        listen()
    }
    
    func listen() {
        Auth.auth().addStateDidChangeListener { [self] (auth, user) in
            switch user == nil {
            case true: signedIn = false
            case false: signedIn = true
            }
        }
    }
}

但是,当我运行这段代码时,出现如下错误:

The default Firebase app has not yet been configured. Add [FIRApp configure]; (FirebaseApp.configure() in Swift) to your application initialization. Read more: (...)

The default FIRApp instance must be configured before the default FIRAuthinstance can be initialized. One way to ensure that is to call [FIRApp configure]; (FirebaseApp.configure() in Swift) in the App Delegate's application:didFinishLaunchingWithOptions: (application(_:didFinishLaunchingWithOptions:) in Swift).

我需要应用程序在初始化步骤有一个单一的真实来源 - 但 applicationWillFinishLaunching 出于某种原因在 StateObject 调用之后调用。

我的应用目前在 ContentView 中声明了这些 StateObject 类,这避免了这些错误,但正如我上面提到的,我需要偏好来共享单一的真实来源。

非常感谢任何帮助!

在 SchedulerApp 中:应用程序只需添加一个 init 来初始化 Firebase。您将不再需要 AppDelegate class(除非您稍后要在那里做其他事情)。

 init() { 
    FirebaseApp.configure()
 }

中所述,您可以使用应用的初始化程序 (init()) 或 AppDelegate 来初始化 Firebase。

使用初始化程序适用于相当多的 Firebase SDK,但也有一些使用方法调配,并且他们希望存在 AppDelegate.

The Ultimate Guide to the SwiftUI 2 Application Life Cycle - SwiftUI 2 中,我深入探讨了新应用程序生命周期的一些细节。

让我们看一下我为那篇文章构建的 sample app 的代码,以及生成的输出:

class AppDelegate: NSObject, UIApplicationDelegate {
  func application(_ application: UIApplication,
                   didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    print("Colors application is starting up. ApplicationDelegate didFinishLaunchingWithOptions.")
    return true
  }
}


@main
struct ColorsApp: App {
  @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
  
  @Environment(\.scenePhase) var scenePhase
  
  init() {
    print("Colors application is starting up. App initialiser.")
  }
  
  var body: some Scene {
    WindowGroup {
      ContentView()
    }
    .onChange(of: scenePhase) { newScenePhase in
      switch newScenePhase {
      case .active:
        print("App is active")
      case .inactive:
        print("App is inactive")
      case .background:
        print("App is in background")
      @unknown default:
        print("Oh - interesting: I received an unexpected new value.")
      }
    }
  }
}

调试控制台输出:

Colors application is starting up. App initialiser.
Colors application is starting up. ApplicationDelegate didFinishLaunchingWithOptions.
App is active

所以应用初始化如下:

  1. 调用了应用程序初始化程序
  2. AppDelegatedidFinishLaunchingWithOptions被称为
  3. scenePhase变为.active

对于您的应用,我建议如下:

  1. 在您应用的初始化程序中初始化 Firebase
  2. 在您应用的初始化程序中,初始化您的模型和其他真实来源,并将它们连接到相应的 Firebase 服务

另一种选择是:

  1. 在您应用的初始化程序中初始化 Firebase
  2. 通过提供默认值(就像您所做的那样)初始化您的模型和事实来源,但暂时不要连接到 Firebase
  3. 实施 ScenePhase 处理程序,并且 - 一旦应用程序进入 .active 状态,“激活”您的模型并告诉它们连接到 Firebase。

第一个选项听起来更简洁,也更容易实施。对我来说:-)