Sponsor Link
環境&対象
- macOS Monterery beta 3
- Xcode 13 beta3
- iOS 15 beta
AppDelegate
UIApplicationDelegateAdaptor を使って、ScenePhase では対応できないイベント対応を、自前の UIApplicateionDelegate に準拠したクラスで対応しているケースがまだまだ多いと思います。
特定のイベントに対応するだけであれば、問題ありませんが、ケースによっては、AppDelegate にデータを保持させているケースがあり、SwiftUI の View とのデータ共有が複雑になりがちで、相互にアクセスすることが必要なケースもあります。
UIApplication.shared.delegate へのアクセス
UIKit であれば、UIApplication.shared.delegate でアクセスできます。
ですが、SwiftUI で @UIApplicationDelegateAdaptor を使用して設定した AppDelegate は、UIApplication.shared.delegate には、セットされていません。
ですので、UIApplication.shared.delegate…. とアクセスしても、期待するデータを取得することはできません。
SwiftUI の ビューから AppDelegate へアクセスする方法
AppDelegate を ObesrvableObject に準拠させる
通常は、AppDelegate は、NSObject, UIApplicationDelegate に準拠させていると思いますが、追加で、ObservableObject にも準拠させます。
ObservableObject は、対象が class であることを要求するだけですので、準拠させるだけで それ以上のコードを必要としません。
必要に応じて、@Published
データの変更を外部に通知したいのであれば、プロパティ定義に @Published を付与します。
アクセスするビューで environmentObject 定義する
アクセスしたいビューで、以下のように定義することで、アクセスが可能となります。
struct ContentView: View {
@EnvironmentObject var appDelegate: MyAppDelegate // アクセスしたいビューで @EnvironmentObject 宣言
var body: some View {
VStack {
Text("Value from AppDelegate \(appDelegate.appDelegateData)") // アクセス(1)
.padding()
Button(action: {
appDelegate.appDelegateData += 1 // アクセス(2)
}, label: {
Text("appDelegateData ++")
})
.padding()
}
.padding()
}
}
@main
struct AppDelegateAsEnvironmentApp: App {
@UIApplicationDelegateAdaptor(MyAppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class MyAppDelegate: NSObject, UIApplicationDelegate, ObservableObject {
@Published var appDelegateData: Int = 19
}
変数に @Published を付与して宣言しているので、変数が変更されると画面が更新されます。
Apple のドキュメントをよ〜〜〜〜く読むと見つかります。
実は、UIApplicationDelegateAdaptor には、同じ引数をとる init が2つ定義されています。渡されるクラスが、Observable に準拠しているかどうかで振る舞いが変わるようになっています。
NSObject と UIApplicationDelegate のみに準拠しているクラスを使用する init は、こちら
NSObject, UIApplicationDelegate, ObservableObject に準拠しているクラスを使用する init は、こちら
2つめの init のドキュメントに、 note として、今回説明したことが説明されています。
UIKit と合わせて説明していますが、macOS での NSApplicationDelegateAdaptor でも同様の説明がされています。
まとめ:SwiftUI から AppDelegate にアクセスする方法
- UIApplicationDelegateAdaptor を使って、AppDelegate 使用を設定する
- AppDelegate に使用するクラスを ObservableObject に準拠させる
- 使用したい SwiftUI の View で、@EnvironmentObject として定義してアクセスする
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
Sponsor Link