Appleのデバイス上で動くアプリで使われる値監視メカニズムは、かつてはCombineフレームワークと共に導入されたObservableObjectプロトコルを使ったものだった。今はObservationフレームワークが使われる。これはSwiftUIをインポートすれば同時に利用できる。
たどえばアプリが2つのViewから構成されているとする。各々のViewには独立して監視対象の変数を定義できる。アプリ環境変数は注入されたViewでの変更がアプリを構成するViewすべてで観測される。
方法1(コード修正箇所少、#Previewコード、Appコードに影響を与えず)
-
環境変数にインスタンスを追加
extension EnvironmentValues { var user: User { get { self[UserKey.self] } set { self[UserKey.self] = newValue } } }
-
ContentViewで環境変数を取り出す(コード抜粋)
struct ContentView: View { // 環境から監視対象Objectを注入 @Environment(\.user) var user var body: some View { ... } }
方法2
-
ContentViewにenvironmentモディファイアを使ってインスタンスを注入する
@main struct EnvironmentVal02App: App { var body: some Scene { WindowGroup { ContentView() .environment(User()) } } }
-
ContentViewで型名を指定してインスタンスを取り出す(コード抜粋)
struct ContentView: View { // 環境から監視対象Objectを注入 @Environment(User.self) var user var body: some View { ... } }
コード全体
-
方法1
struct UserKey: EnvironmentKey { static var defaultValue = User() } extension EnvironmentValues { var user: User { get { self[UserKey.self] } set { self[UserKey.self] = newValue } } } @Observable class User { var firstName: String = "塩中" ObservationIgnored var lastName: String = "優子" } struct ContentView: View { // 環境から監視対象Objectを注入 @Environment(\.user) var user var body: some View { Text(user.firstName + user.lastName) Button { user.firstName = "青池" user.lastName = "紘一" } label: { Text("名前を変える") } } } #Preview { ContentView() .frame(width: 400, height: 100) }
-
方法2
@Observable class User { var firstName: String = "塩中" var lastName: String = "優子" } struct ContentView: View { // 環境から監視対象Objectを注入 @Environment(User.self) var user var body: some View { Text(user.firstName + user.lastName) Button { user.firstName = "青池" user.lastName = "紘一" } label: { Text("名前を変える") } } } #Preview { ContentView() .environment(User()) .frame(width: 400, height: 100) } @main struct EnvironmentVal02App: App { var body: some Scene { WindowGroup { ContentView() .environment(User()) } } }