Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 515
Mister22 Avatar asked Aug 26 '20 12:08

Mister22


People also ask

What is the use of AppDelegate in iOS?

Your app delegate object manages your app's shared behaviors. The app delegate is effectively the root object of your app, and it works in conjunction with UIApplication to manage some interactions with the system.

What is AppDelegate in Swift iOS?

The Delegate Pattern in Swift In Swift, a delegate is a controller object with a defined interface that can be used to control or modify the behavior of another object.

What is SwiftUI app life cycle?

It's an iOS app's “main” function, the first one called during the lifetime of the app. You typically use it for: Initial configuration of 3rd-party components and frameworks, such as setting up Firebase, Bugsnag, Realm, OneSignal, Parse Server, Reachability services, and so on.


2 Answers

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 = ...
    }
like image 190
Asperi Avatar answered Oct 26 '22 13:10

Asperi


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

like image 3
svena Avatar answered Oct 26 '22 12:10

svena