Tana Gone
Tana Gone
1 min read

Categories

Appleのデバイス上で動くアプリで使われる値監視メカニズムは、かつてはCombineフレームワークと共に導入されたObservableObjectプロトコルを使ったものだった。今はObservationフレームワークが使われる。これはSwiftUIをインポートすれば同時に利用できる。

たどえばアプリが2つのViewから構成されているとする。各々のViewには独立して監視対象の変数を定義できる。アプリ環境変数は注入されたViewでの変更がアプリを構成するViewすべてで観測される。

方法1(コード修正箇所少、#Previewコード、Appコードに影響を与えず)

  1. 環境変数にインスタンスを追加

    extension EnvironmentValues {
      var user: User {
        get { self[UserKey.self] }
        set { self[UserKey.self] = newValue }
      }
    }
    
  2. ContentViewで環境変数を取り出す(コード抜粋)

    struct ContentView: View {
      // 環境から監視対象Objectを注入
      @Environment(\.user) var user
      var body: some View {
      ...
      }
    }
    

方法2

  1. ContentViewにenvironmentモディファイアを使ってインスタンスを注入する

    @main
    struct EnvironmentVal02App: App {
      var body: some Scene {
        WindowGroup {
          ContentView()
          .environment(User())
        }
      }
    }
    
  2. ContentViewで型名を指定してインスタンスを取り出す(コード抜粋)

    struct ContentView: View {
      // 環境から監視対象Objectを注入
      @Environment(User.self) var user
      var body: some View {
      ...
      }
    }
    

コード全体

  1. 方法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. 方法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())
        }
      }
    }