ObservableObject
Foundation に定義されている のは、Combine の ObservableObject の typealias。
ObservableObject は、View に対して状態変化を通知できる/View がその状態変化を購読できる class。
https://rhonabwy.com/2021/02/13/nested-observable-objects-in-swiftui/
View は ObservableObject を @StateObject や @ObservableObject として保持している時、その objectWillchange を購読しているらしい。ObservableObject には @Published な property を定義できて、@Published な property に変更が加わると、objectWillchange が発火される。
https://qiita.com/yimajo/items/8846207d2b7a17ace809
定義
定義は以下のようになっている。求めているのは objectWillChange のみ。ObservableObject の値が変化する直前に、この Publisher から値を送出される必要がある。Publisher はデフォルトで用意されているものがあるが、差し替えることもできる。
code:swift
public protocol ObservableObject: AnyObject {
associatedtype ObjectWillChangePublisher: Publisher
= ObservableObjectPublisher where Self.ObjectWillChangePublisher.Failure == Never
// objectが変化する "前に" 値を送出する
var objectWillChange: Self.ObjectWillChangePublisher { get }
}
用途
View は値型であり、描画後はすぐにインスタンスが破棄される。一方で、ObservableObject は参照型であり、データのライフサイクルの管理や、副作用の処理、既存のドメインロジックとの統合などが行える。ObservableObject は View に対して表示すべきデータを提供する存在であるため、View とデータ依存の境界としての役割を持つとも言える。
極端に言えば、アプリの全ての状態を1つのObservableObjectで管理して、各Viewは同一のObservableObjectを参照する、といったこともできる。
code:text
+------+ +----------+------------+
| View | <==============| | Data Model |
+------+ | | +-+ |
| |Observable| +-+ +-+ |
+---------+ | Object | +-+ |
| | | | +-+ |
+------+ +------+ | | +-+ |
| View | | View | <===| | |
+------+ +------+ +----------+------------+
^ ||
\======================/
作成方法
ObservableObject は大抵、@Published property wrapper とともに利用する。@Published property wrapper は、Publisher を外部に公開することで、そのプロパティを観測可能にする property wrapper。ObservableObject で @Published な値に変更が加わった時、その willSet のタイミング で objectWillChange に値が送出され、値の変更を外部に通知できる。
ObservableObject が Dependency (SwiftUI) として追加されると、SwiftUI はその ObservableObject の objectWillChange を自動的に購読する。そして、objectWillChange から値が送出される度に View を更新する。なぜ didChange ではなく willChange なのかというと、事前に変更する対象を知ることで、SwiftUI が全ての変更を1回の更新にまとめるから。
利用方法
何の property wrapper も、ObservableObject を Dependency (SwiftUI) として管理する。
@ObservedObject
インスタンスの保持はしない
@StateObject
ObservableObject のライフサイクルを View の Lifetime (SwiftUI) と一致させる
SwiftUI によってインスタンスが保持される
body の実行の直前にインスタンス化される
@EnvironmentObject
上流の View と、そこから離れた下流の View の間で同一の ObservableObject を共有できる
.environmentObject() View Modifier で注入し、@EnvironmentObject property wrapper で取得する
参考
ObservableObject | Apple Developer Documentation
Data Essentials in SwiftUI - WWDC 2020