在 StateObject 初始化之前应用程序委托中的 Firebase 初始化
Posted
技术标签:
【中文标题】在 StateObject 初始化之前应用程序委托中的 Firebase 初始化【英文标题】:Firebase initialisation in application delegate before StateObject initialisation 【发布时间】:2021-01-04 15:51:37 【问题描述】:我正在用 SwiftUI 编写一个应用程序并使用 Firebase 作为我的后端。
我有一个可用的首选项面板,它由应用程序本身内的一个模式组成,但我想利用 macOS 的一致首选项窗口,其中包括菜单选项以及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
但是,当我运行此代码时,出现以下错误:
尚未配置默认 Firebase 应用。将
[FIRApp configure];
(Swift 中的FirebaseApp.configure()
)添加到您的应用程序初始化中。阅读更多:(...)
必须先配置默认 FIRApp 实例,然后才能初始化默认 FIRAuthinstance。确保这一点的一种方法是在 App Delegate 的
application:didFinishLaunchingWithOptions:
(Swift 中为application(_:didFinishLaunchingWithOptions:)
)中调用[FIRApp configure];
(Swift 中为FirebaseApp.configure()
)。
我需要应用程序在初始化步骤有一个单一的事实来源 - 但由于某种原因 applicationWillFinishLaunching 在 StateObject 调用之后调用。
我的应用目前在 ContentView 中声明了这些 StateObject 类,这可以避免这些错误,但正如我上面提到的,我需要偏好来共享单一的事实来源。
非常感谢任何帮助!
【问题讨论】:
【参考方案1】:在 SchedulerApp 中:应用只需添加一个 init 来初始化 Firebase。您将不再需要 AppDelegate 类(除非您稍后要在其中做其他事情)。
init()
FirebaseApp.configure()
【讨论】:
【参考方案2】:如Where to configure Firebase in my ios app in the new SwiftUI App life cycle without AppDelegate and SceneDelegate? 中所述,您可以使用应用的初始化程序 (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
所以应用初始化如下:
-
应用初始化程序被调用
AppDelegate
的didFinishLaunchingWithOptions
被调用
scenePhase
更改为 .active
对于您的应用,我建议如下:
-
在应用的初始化程序中初始化 Firebase
在您应用的初始化程序中,初始化您的模型和其他事实来源,并将它们连接到相应的 Firebase 服务
另一种选择是:
-
在应用的初始化程序中初始化 Firebase
通过提供默认值(如您所做的那样)来初始化您的模型和事实来源,但暂时不要连接到 Firebase
实现
ScenePhase
处理程序,并且 - 一旦应用进入 .active
状态,“激活”您的模型并告诉它们连接到 Firebase。
第一个选项听起来更清晰,更容易实现。对我来说:-)
【讨论】:
以上是关于在 StateObject 初始化之前应用程序委托中的 Firebase 初始化的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI:如何在父视图中初始化新的 StateObject?
如何防止 SwiftUI 像使用 @StateObject 一样重新初始化我的包装属性?