问题
I'm using SwiftUI's new app lifecycle coming in iOS 14.
However, I'm stuck at how to access my AppState (single source of truth) object in the AppDelegate.
I need the AppDelegate to run code on startup and register for notifications (didFinishLaunchingWithOptions
, didRegisterForRemoteNotificationsWithDeviceToken
, didReceiveRemoteNotification
) etc.
I am aware of @UIApplicationDelegateAdaptor
but then I can not e.g. pass an object through to the AppDelegate with a constructor. I guess the other way round (creating the AppState in the AppDelegate and then accessing it in MyApp) does not work either.
@main
struct MyApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@State var appState = AppState()
var body: some Scene {
WindowGroup {
ContentView().environmentObject(appState)
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// access appState here...
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// ...and access appState here
}
}
class AppState: ObservableObject {
// Singe source of truth...
@Published var user: User()
}
Any help is appreciated. Maybe there is currently no way to achieve this, and I need to convert my app to use the old UIKit lifecycle?
回答1:
Use shared instance for AppState
class AppState: ObservableObject {
static let shared = AppState() // << here !!
// Singe source of truth...
@Published var user = User()
}
so you can use it everywhere
struct MyApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject var appState = AppState.shared
// ... other code
}
and
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// ...and access appState here
AppState.shared.user = ...
}
回答2:
Is there a reason why you need to run the code in app delegate?
If you are using new app lifecycle, why not trigger your code from WindowGroup.onChange()
struct MyScene: Scene {
@Environment(\.scenePhase) private var scenePhase
@StateObject private var cache = DataCache()
var body: some Scene {
WindowGroup {
MyRootView()
}
.onChange(of: scenePhase) { newScenePhase in
if newScenePhase == .background {
cache.empty()
}
}
}
}
Apple Documentation Link
Managing scenes in SwiftUI by Majid
来源:https://stackoverflow.com/questions/63597783/accessing-appstate-in-appdelegate-with-swiftuis-new-ios-14-life-cycle