【问题标题】:Firebase initialisation in application delegate before StateObject initialisation在 StateObject 初始化之前应用程序委托中的 Firebase 初始化
【发布时间】: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 类,这可以避免这些错误,但正如我上面提到的,我需要偏好来共享单一的事实来源。

非常感谢任何帮助!

【问题讨论】:

    标签: ios swift firebase swiftui appdelegate


    【解决方案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
      

      所以应用初始化如下:

      1. 应用初始化程序被调用
      2. AppDelegate 的didFinishLaunchingWithOptions 被调用
      3. scenePhase 更改为 .active

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

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

      另一种选择是:

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

      第一个选项听起来更清晰,更容易实现。对我来说:-)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-16
        • 2013-08-03
        • 2021-12-20
        • 1970-01-01
        • 2021-06-21
        • 1970-01-01
        相关资源
        最近更新 更多