@StateObject
とは?
@StateObject
は SwiftUI において ObservableObject
を管理するためのプロパティラッパーです。ビューのライフサイクルを通じて ObservableObject
のインスタンスを保持し、データが更新されるとビューを再描画する役割を持ちます。
基本的な使い方
import SwiftUI
class CounterViewModel: ObservableObject {
@Published var count = 0
func increment() {
count += 1
}
}
struct CounterView: View {
@StateObject private var viewModel = CounterViewModel()
var body: some View {
VStack {
Text("\(viewModel.count)")
.font(.largeTitle)
Button("Increment") {
viewModel.increment()
}
}
}
}
この例では、@StateObject
を使用して CounterViewModel
のインスタンスを作成し、count
の変更に応じてビューを更新しています。
self._model = StateObject(wrappedValue: ...)
の活用
通常、@StateObject
は次のように初期化します。
@StateObject private var viewModel = CounterViewModel()
しかし、ビューの init
内で @StateObject
を初期化する必要がある場合は、以下のように self._model = StateObject(wrappedValue: ...)
を使います。
なぜ self.model =
ではなく self._model =
なのか?
SwiftUI では @StateObject
は ビューのライフサイクルを通じてオブジェクトを一度だけ作成する べきものとされています。そのため、init
内で self.model = CounterViewModel(data: data)
のように直接代入することはできません。
self._model = StateObject(wrappedValue: ...)
を使うことで、以下のように ObservableObject
を安全に初期化できます。
実際のコード例
import SwiftUI
class CounterViewModel: ObservableObject {
@Published var count: Int
init(initialCount: Int) {
self.count = initialCount
}
func increment() {
count += 1
}
}
struct ContentView: View {
@StateObject private var model: CounterViewModel
init(initialCount: Int) {
self._model = StateObject(wrappedValue: CounterViewModel(initialCount: initialCount))
}
var body: some View {
VStack {
Text("\(model.count)")
.font(.largeTitle)
Button("Increment") {
model.increment()
}
}
}
}
このパターンが必要なケース
init
で外部から渡されたデータを使ってObservableObject
を初期化したい場合- 複雑な
ObservableObject
の初期化ロジックが必要な場合 - SwiftUI の制約により、直接
self.model = ...
できない場合
@ObservedObject
や @EnvironmentObject
との違い
@ObservedObject
-
ObservableObject
を 外部から渡して 使用する。 -
View
のライフサイクルではObservableObject
を作成しない。
struct SomeView: View {
@ObservedObject var viewModel: CounterViewModel
}
@EnvironmentObject
-
@EnvironmentObject
は@ObservedObject
の一種で、SwiftUI のEnvironment
を通じてオブジェクトを受け取る。
struct SomeOtherView: View {
@EnvironmentObject var viewModel: CounterViewModel
}
@StateObject
の適用タイミング
使用する場面 | 適切なプロパティラッパー |
---|---|
ビュー内で ObservableObject のライフサイクルを管理したい |
@StateObject |
すでに作成された ObservableObject を親ビューから渡したい |
@ObservedObject |
Environment を通じて複数のビューで共有したい |
@EnvironmentObject |