@EnvironmentObjectの中身をSceneDelegateで使いたい

SwiftUI

 アプリ全体で使用している変数をアプリ終了時や復帰時などにSave/Loadする場合は、SceneDelegateでEnvironmentObjectを使用したい場合があります。

 EnvironmentObjectで使用するクラスはObservableObjectです。なのでSceneDelegateでは@ObservedObjectで宣言しておき、その変数をViewに渡すことでSceneDelegateからアクセスできます。

class ObsObj: ObservableObject {
    @Published var text:String = "Test"
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    @ObservedObject var envObj = ObsObj()
    
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        let contentView = ContentView().environmentObject(envObj)

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        envObj.Test()
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
    }

    func sceneWillResignActive(_ scene: UIScene) {
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
    }
}

 @EnvironmentObjectはViewからはどこからでもアクセス出来て便利ですが、SceneDelegateで使用した場合は注意が必要です。


 ダメなパターン。

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?
    @EnvironmentObject var envObj:ObsObj
    
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        let contentView = ContentView().environmentObject(ObsObj())

    //以下略
    }
}

Fatal error: No ObservableObject of type ObsObj found. A View.environmentObject(_:) for ObsObj may be missing as an ancestor of this view.: file SwiftUI, line 0

 ビルドは通りますが、いざ実行すると上記のエラーが出ます。要は使用するクラスよりも上位のクラスで.environmentObject()を実行しろということです。

 rootViewをSceneDelegateで設定しているので、親のViewはおそらく無いと思いますのでObservedObjectで宣言する必要があります。

 EnvironmentObjectそのままを使う方法があればコメントにお願いいたします。

コメント

タイトルとURLをコピーしました