【Swift UI】@ObservedObjectの意味と使い方!クラスとプロトコルとの関係
この記事からわかること
- Swiftの@ObservedObjectとは?
- 意味や使い方、メリット
- ObservableObjectプロトコルとクラスでの定義方法
- @Publishedの使い方
- ビュー間でクラスのデータを共有する方法
index
[open]
\ アプリをリリースしました /
環境
- Xcode:26.0.1
- iOS:26
- Swift:6
- macOS:Tahoe 26.0.1
Swift UIでクラスのプロパティの更新を監視するために使用する「@ObservedObject」や「@Published」などの使い方やメリットをまとめていきたいと思います。
※ Swift5.9 / iOS17以降からはObservationフレームワークが登場しています。参考にしてください。
@ObservedObjectとは?
@ObservedObjectは@Bindingなどと同じくSwift5.1から導入された「Property Wrapper(プロパティラッパ)」の1つです。プロパティラッパの特徴はプロパティ(変数)に対する操作や処理をカプセル化して定義することで特定のキーワードを追加するだけで任意の動作や挙動を行わせることができるデータ構造です。
@ObservedObjectは@Publishedと組み合わせて使用することで、クラスのプロパティの変更を監視し、更新された時にビューに表示されている値も更新するためのプロパティラッパです。つまりクラスのプロパティの更新がリアルタイムにビューに反映されるようになります。
@Publishedもプロパティラッパの1種でCombineフレームワークから提供されている機能の1つです。@Publishedが付与されたプロパティは監視状態になります。これで値が変更された時にその変化を感知することができるようになります。
@Publishedが付与されているプロパティが更新され、ビューが再描画されるためにはそのクラスがObservedObjectプロトコルに準拠しインスタンス化した変数に@ObservedObject・@StateObject・@EnvironmentObjectのいずれかが指定されている必要があります。
ポイント
- @ObservedObjectはProperty Wrapper(プロパティラッパ)の1つ
- クラスのプロパティの更新がリアルタイムにビューに反映する役割
- 監視するプロパティには@Publishedを付与
- クラスはObservableObjectプロトコル準拠
- インスタンス化した変数に@ObservedObject・@StateObject・@EnvironmentObjectのいずれかを付与
Swift UIでの使い方
クラスで定義しているプロパティの値が変化する際にビュー(表示)も同時に更新したい場合に@ObservedObjectを使います。使う流れは以下の通りです。
- クラスをObservableObjectプロトコルに準拠して定義
- 監視したいプロパティに@Publishedを付与
- インスタンス化した変数に@ObservedObjectを付与
簡単なカウンターアプリを想定して実装方法を見ていきます。
1.クラスをObservableObjectプロトコルに準拠して定義
カウンターロジックを持つViewModel側のクラスにObservableObjectプロトコルを準拠させます
// ObservableObjectを継承
final class CounterViewModel: ObservableObject {
var count = 0
}
2.監視したいプロパティに@Publishedを付与
変更を監視したいプロパティに@Publishedを付与します。
final class CounterViewModel: ObservableObject {
@Published private(set) var count = 0
func increment() { count += 1 }
}
プロパティをlet(定数)で定義してしまうとProperty wrapper can only be applied to a 'var'というエラーになるのでvarで宣言しておきます。
3.インスタンス化した変数に@ObservedObjectを付与
ObservedObjectプロトコルに準拠させたクラスをインスタンス化し変数に格納します。その際に@ObservedObjectを付与します。これでクラスのプロパティの値が変化した時にビューも連動して更新されるようになります。
struct ContentView: View {
// ObservableObjectを監視する
@ObservedObject private var viewModel = CounterViewModel()
var body: some View {
VStack {
Text("Count: \(viewModel.count)")
Button {
viewModel.increment()
} label: {
Text("increment")
}
}
}
}
上記の例ではインクリメント処理が実行されるたびにcountプロパティが変化します。その変化をView側でも検知し再描画が走るためTextの中身も常に最新の値に更新されるようになります。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。





