'Accessing AppState in AppDelegate with SwiftUI's new iOS 14 life cycle
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?
Solution 1:[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 = ...
}
Solution 2:[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()
}
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | svena |