iosswiftswiftui

How to share an object between AppDelegate and SceneDelegate


I am already using AppDelegate for registering with APNs, but since it does not support the applicationWillResignActive() and applicationWillEnterForeground() functions which handled by the SceneDelegate as explained in here.

I want both delegates to have the access to my client instance. Currently, the AppDelegate instantiates the client as its property and then it is passed to the scene as an environmentObject:

import SwiftUI

@main
struct app1App: App {

  @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

  var body: some Scene {
    WindowGroup {
      MainView().environmentObject(appDelegate.client)
    }
  }
}

class AppDelegate: NSObject, UIApplicationDelegate {
  
  let client : Client = Client()
  // other Notifications related functions
}

When I declare my client in views as:

@EnvironmentObject var client: Client

then the views have the access to the client's methods, however, the same approach does not work when I declare it in the SceneDelegate:

class SceneDelegate: NSObject, UIWindowSceneDelegate {

  @EnvironmentObject var client: Client

  func sceneWillEnterForeground(_ scene: UIScene) {
    self.client.disconnect()  // This fails in runtime!!!
  }
}

The error says it is expecting an observable object, but my object is environmentObject:

Thread 1: Fatal error: No ObservableObject of type Client found. A View.environmentObject(_:) for Client may be missing as an ancestor of this view.

What's the proper way to provide the access to the client by the functions from the SceneDeleagte?


Solution

  • Just need help with sharing the client between the two delegates - any suggestions?

    If it is app-wide to be shared then the simplest is to make it global

    let client : Client = Client()    // << create here
    
    class AppDelegate: NSObject, UIApplicationDelegate {
      // access `client` here directly
      // other Notifications related functions
    }
    
    class SceneDelegate: NSObject, UIWindowSceneDelegate {
    
      func sceneWillEnterForeground(_ scene: UIScene) {
        // access `client` here directly
        client.disconnect()  // This fails in runtime!!!
      }
    }