🐡

SwifUIのStateObject, ObservedObject, EnvironmentObjectで出来ること

2022/08/06に公開

使用優先度

違いがわからない場合、以下のような優先度で使用するものを選ぶのもいいと思います。

  1. @StateObject // 最優先
  2. @ObservedObject
  3. @EnvironmentObject

StateObjectで出来ないこと

以下のことはできないので、以下のようなことがしたい場合は、ObservedObjectを使用しましょう

MainViewでカウントアップしてSubViewでカウントを表示する

struct ContentView: View {
  var body: some View {
    MainView()
  }
}

class Counter: ObservableObject {
  var count: Int

  init(count: Int) {
    self.count = count
  }
}

struct SubView: View {
  @StateObject var counter: Counter
  let date = Date()

  var body: some View {
    Text("\(counter.count)")
    Text(date.formatted(.iso8601))
  }
}

struct MainView: View {
  @State var count: Int = 0

  var body: some View {
    Button("Count++") { count += 1 }

    SubView(counter: .init(count: count))
  }
}

EnvironmentObjectで出来ること

EnvironmentObjectは何もしなくても子Viewの子Viewに対してObjectを使用することができます。

以下の例ではSubSubViewを表示しているSubViewはEnvironmentに関して何も触れられていないですが、SubSubViewでは利用可能です。

class Counter: ObservableObject {
  var count: Int

  init(count: Int) {
    self.count = count
  }
}

struct SubView: View {
  var body: some View {
    SubSubView()
  }
}

struct SubSubView: View {
  @EnvironmentObject var counter: Counter

  let date = Date()

  var body: some View {
    Text("\(counter.count)")
    Text(date.formatted(.iso8601))
  }
}

struct MainView: View {
  @State var count: Int = 0

  var body: some View {
    Button("Count++") { count += 1 }

    SubView()
      .environmentObject(Counter(count: count))
  }
}

まとめ

Name Description
StateObject 自身のViewことしかわからない
ObservedObject 親Viewのことも監視(Observe)している
EnvironmentObject どこかの親ViewでenvironmentObjectされていいれば使用可能

Tips

@Binding@StateObjectを組み合わせれば@ObservedObject的な形で利用可能だが、ほぼうまくいかないので諦めが必要な場合あり

Discussion