はじめに
iOS17以降からObservationという新たな状態監視のFrameworkが使用できるようになりました。
しかし、状態監視のFrameworkとしてはすでにCombineが存在しています。
今回は新たに登場したObservationとCombineを比較しながら、Observationについて見ていきます。
Observationについて
まずは、ObservationとCombineの書き方を比較していきます。
今回はボタンをタップすると表示されている数字がインクリメントしていくViewをそれぞれ作成して比較していきます。
Combineによる状態監視
CounterViewStateはObservableObjectを実装し、@Publishedを付与したプロパティの値を監視しています。
CounterViewはStateObjectを使ってCounterViewStateを監視可能なオブジェクトとしてインスタンス化することで、CounterViewStateの状態が変化した際にViewを再描画します。
import Combine
final class CounterViewState: ObservableObject {
@Published private(set) var count = 0
func increment() {
count += 1
}
}
import SwiftUI
struct CounterView: View {
@StateObject private var state: CounterViewState = .init()
var body: some View {
VStack {
Text(state.count.description)
Button("increment", action: {
state.increment()
})
}
.padding()
}
}
Observationによる状態監視
@Observableはマクロで実装されている機能です。
@Observable付与することで状態の変化を監視するようコードを変換してくれます。
Combineと違い、@Publishedをプロパティに付与しなくとも値を監視してくれます。
CounterViewは@Stateを使ってCounterViewStateの値を監視、更新時にViewを再描画します。
import Observation
@Observable final class CounterViewState {
private(set) var count = 0
func increment() {
count += 1
}
}
import SwiftUI
struct CounterView: View {
@State private var state: CounterViewState = .init()
var body: some View {
VStack {
Text(state.count.description)
Button("increment", action: {
state.increment()
})
}
.padding()
}
}
ObservationとCombineの違いについて
それぞれの実装を見てきました。
では実際には、ObservationとCombineにはどういった違いがあるかを見ていきたいと思います。
ObservationとCombineには大きく二つの違いがあります。
監視対象のプロパティの定義方法の違い
Combineでは監視対象のプロパティには@Publishedをつける必要があります。
Observationでは必要なプロパティ一つ一つに@Publishedをつけるといった冗長な作業は必要なく、通常通り定義するだけで問題ありません。
@Publishedをプロパティ一つ一つにつけていくのは冗長だったので、付与する必要がなくなったのは単純に嬉しいですね。
オブジェクトの監視対象の違い
ObservableObjectを監視する場合、プロパティ毎の個別の変更を監視しているわけではなくObservableObjectのobjectWillChange Publisherを監視しています。
objectWillChangeはObservableObjectのいずれかのプロパティが変更された際に発火します。
なので、Viewの描画に必要のないプロパティが更新された場合でも、不必要に再描画が走ってしまう等の可能性があります。
Observation では、各プロパティを個別に監視しているため、関係のない値の変更によって不要な更新が走るといったことはありません。
Observationで追加されたマクロ
Observationには@Observableの他に2つのマクロが追加されており、Observableのプロパティに対してアノテーションとして付与することができます。
@ObservationTracked
@ObservationTrackedをプロパティに付与することで、プロパティの変更を検知するようコードを変換します。
が、基本的に開発者が@ObservationTrackedを使うことはありません。
@Observableマクロによって、対象のプロパティを@ObservationTrackedを付与した形にコードを変換してくれるため、開発者が@ObservationTrackedを意識することはないでしょう。
@ObservationIgnored
@ObservationIgnoredをプロパティに付与することで、該当のプロパティを監視しないようコードを変換します。
Observationでは、Combineのように@Publishedを記載しなくてもプロパティの監視ができるようになっている反面、デフォルトで全てのプロパティを監視するようになっているので、監視の必要がない値には@ObservationIgnoredをつけてあげる必要があります。
import Observation
@Observable final class CounterViewState {
private(set) var count = 0 // 監視する
@ObservationIgnored private(set) var title = "" // 監視しない
}
最後に
CombineよりもObservationの違いを見てきましたが、やはりObservationの方が使いやすそうだなといった印象です。
ただ、ObservationはiOS17以降でしか使えないため、既存のアプリに対しては即導入ということはできないので今後に期待です!
また、何かご意見等ありましたらコメントいただけますと幸いです。
どうぞよろしくお願いいたします。