SwiftUI ObservableObject と @Published の基本
SwiftUI でビューとデータを結びつける仕組みの中心にあるのが ObservableObject プロトコルだ。このプロトコルに準拠したクラスは、自身の変更をビューに通知できるようになる。変更通知のトリガーとなるのが @Published プロパティラッパーであり、この2つの組み合わせが SwiftUI のリアクティブな UI 更新を支えている。
ObservableObject の役割
ObservableObject は Combine フレームワークで定義されたプロトコルで、objectWillChange というパブリッシャーを自動的に持つ。ビューがこのオブジェクトを監視していると、objectWillChange が発火したタイミングでビューの再描画が走る。
class CounterModel: ObservableObject {
@Published var count = 0
func increment() {
count += 1
}
}上のコードでは CounterModel が ObservableObject に準拠し、count プロパティに @Published を付けている。count の値が変わるたびに objectWillChange が自動発火し、このモデルを監視しているビューが再描画される。
@Published の仕組み
@Published はプロパティラッパーの一種で、値の変更前に objectWillChange.send() を呼び出す。つまり、開発者が手動で通知を送る必要はなく、プロパティに代入するだけで自動的にビューへ伝わる。
プロパティの変更が自動でビューに通知される。宣言するだけで Combine のパブリッシャーとして機能する。
プロパティが変更されてもビューには通知されない。内部的な状態管理にのみ使う場合に適している。
すべてのプロパティに @Published を付ける必要はない。ビューの表示に関係しない内部状態、たとえばキャッシュやフラグなどは @Published なしで宣言すればよい。不要な再描画を避けるために、通知が必要なプロパティだけに絞ることがパフォーマンス上も重要になる。
ビューからの利用
ObservableObject をビューで使うには、@StateObject または @ObservedObject でインスタンスを保持する。ここでは基本的な利用例として @StateObject を使った形を示す。
struct CounterView: View {
@StateObject private var model = CounterModel()
var body: some View {
VStack {
Text("\(model.count)")
.font(.largeTitle)
Button("increment") {
model.increment()
}
}
}
}@StateObject はビューのライフサイクルに紐づいてインスタンスを管理する。ビューが再描画されてもインスタンスは保持され、count の値が失われることはない。
objectWillChange の手動発火
通常は @Published に任せておけば十分だが、より細かい制御が必要な場合は objectWillChange を手動で呼べる。たとえば複数のプロパティを一括で変更したあと、まとめて1回だけ通知したいケースだ。
class ProfileModel: ObservableObject {
var name = ""
var age = 0
func update(name: String, age: Int) {
objectWillChange.send()
self.name = name
self.age = age
}
}この場合 name と age に @Published は付けず、update メソッド内で明示的に send() を呼んでいる。通知は1回だけ発火するため、2つのプロパティの変更に対してビューの再描画も1回で済む。
クラス限定の理由
ObservableObject はクラス専用のプロトコルであり、構造体には適用できない。これは SwiftUI の監視メカニズムが参照型であることを前提としているためだ。
構造体は値型なので、変更のたびにコピーが生成される。一方クラスは参照型であり、複数のビューが同じインスタンスを共有して参照セマンティクスで監視できる。
同一のオブジェクトを複数箇所から参照し、変更を共有できる仕組み。
この参照型という性質が、親ビューから子ビューへモデルを渡す場面で威力を発揮する。どのビューから変更しても同じインスタンスが更新されるため、アプリ全体でデータの一貫性を保てる。
まとめ
ObservableObject と @Published は SwiftUI のデータフロー設計における基盤だ。@Published を付けたプロパティが変わればビューが自動で再描画されるという単純な仕組みだが、どのプロパティに @Published を付けるか、手動通知をどう使い分けるかで、アプリのパフォーマンスと設計の柔軟性が変わってくる。