SwiftUI | @ObservedObjectと@EnvironmentObjectの違い

変数

SwiftUIの@ObservedObjectと@EnvironmentObjectの違いを説明する。

結論

両者とも目的は同じ。やり方が違うだけ。

  • 両者とも目的は異なるView間で変数の値を連動させること。
  • @ObservedObjectも@EnvironmentObjectを付けてObservableObjectに準拠するclassの型の変数を定義すると、そのclassの@Publishedを付けた変数は異なるView間で値が連動する。
  • ObservableObjectに準拠するclassのインスタンスをViewに渡す際のやり方が違う。
    – @ObservedObjectは個々のViewにそれぞれインスタンスを渡す。
    – @EnvironmentObjectはあるViewに.environmentObject(インスタンス名)でインスタンスを渡す。それだけでそのView内の個々のViewはそのインスタンスと連動する。

具体例

下記Appを例に説明する。

  • 親Viewのボタンをタップすると親ViewのヨシヒコのHPが10減る。
  • 子Viewのボタンをタップすると子ViewのヨシヒコのHPが10回復する。
  • 親Viewと子ViewのヨシヒコのHPは連動して変化する。

設計イメージ

@ObservedObjectを使う場合

@EnvironmentObjectを使う場合

コード

@ObservedObjectを使う場合

import SwiftUI

struct ContentView: View {
    @StateObject var ヨシヒコ = ゆうしゃ()
    var body: some View {
        HStack {
            // 親View
            VStack {
                Text("親View")
                Text("ヨシヒコのHP : \(String(ヨシヒコ.HP))")
                Button("ヨシヒコを攻撃") { ヨシヒコ.HP -= 10 }
                    .buttonStyle(.borderedProminent)
            }
            .padding()
            .frame(width: 200)
            
            // 子View
            子View(キャラ: ヨシヒコ)

        }
    }
}

class ゆうしゃ: ObservableObject {
    @Published var HP: Int = 100
}

struct 子View: View {
    @ObservedObject var キャラ: ゆうしゃ
    var body: some View {
        VStack {
            Text("子View")
            Text("ヨシヒコのHP : \(String(キャラ.HP))")
            Button("ヨシヒコを回復") { キャラ.HP += 10 }
                .buttonStyle(.borderedProminent)
        }
        .padding()
        .frame(width: 200)
        .border(Color.black, width: 1)
    }
}

@EnvironmentObjectを使う場合

import SwiftUI

struct ContentView: View {
    @StateObject var ヨシヒコ = ゆうしゃ()
    var body: some View {
        HStack {
            // 親View
            VStack {
                Text("親View")
                Text("ヨシヒコのHP : \(String(ヨシヒコ.HP))")
                Button("ヨシヒコを攻撃") { ヨシヒコ.HP -= 10 }
                    .buttonStyle(.borderedProminent)
            }
            .padding()
            .frame(width: 200)
            
            // 子View
            子View()

        }
        .environmentObject(ヨシヒコ)
    }
}

class ゆうしゃ: ObservableObject {
    @Published var HP: Int = 100
}

struct 子View: View {
    @EnvironmentObject var キャラ: ゆうしゃ
    var body: some View {
        VStack {
            Text("子View")
            Text("ヨシヒコのHP : \(String(キャラ.HP))")
            Button("ヨシヒコを回復") { キャラ.HP += 10 }
                .buttonStyle(.borderedProminent)
        }
        .padding()
        .frame(width: 200)
        .border(Color.black, width: 1)
    }
}

差分

左が@ObservedObjectを使う場合、右が@EnvironmentObjectを使う場合

まとめ

SwiftUIの@ObservedObjectと@EnvironmentObjectの違いを説明した。

コメント

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