21
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

iOS17以降から使えるObservationについて

Posted at

はじめに

iOS17以降からObservationという新たな状態監視のFrameworkが使用できるようになりました。
しかし、状態監視のFrameworkとしてはすでにCombineが存在しています。
今回は新たに登場したObservationCombineを比較しながら、Observationについて見ていきます。

Observationについて

まずは、ObservationCombineの書き方を比較していきます。
今回はボタンをタップすると表示されている数字がインクリメントしていくViewをそれぞれ作成して比較していきます。

Combineによる状態監視

CounterViewStateObservableObjectを実装し、@Publishedを付与したプロパティの値を監視しています。
CounterViewStateObjectを使ってCounterViewStateを監視可能なオブジェクトとしてインスタンス化することで、CounterViewStateの状態が変化した際にViewを再描画します。

CounterViewState.swift
import Combine

final class CounterViewState: ObservableObject {
    @Published private(set) var count = 0

    func increment() {
        count += 1
    }
}

CounterView.swift
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を再描画します。

CounterViewState.swift
import Observation

@Observable final class CounterViewState {
    private(set) var count = 0

    func increment() {
        count += 1
    }
}

CounterView.swift
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()
    }
}

ObservationCombineの違いについて

それぞれの実装を見てきました。
では実際には、ObservationCombineにはどういった違いがあるかを見ていきたいと思います。
ObservationCombineには大きく二つの違いがあります。

監視対象のプロパティの定義方法の違い
Combineでは監視対象のプロパティには@Publishedをつける必要があります。
Observationでは必要なプロパティ一つ一つに@Publishedをつけるといった冗長な作業は必要なく、通常通り定義するだけで問題ありません。
@Publishedをプロパティ一つ一つにつけていくのは冗長だったので、付与する必要がなくなったのは単純に嬉しいですね。

オブジェクトの監視対象の違い
ObservableObjectを監視する場合、プロパティ毎の個別の変更を監視しているわけではなくObservableObjectobjectWillChange Publisherを監視しています。
objectWillChangeObservableObjectのいずれかのプロパティが変更された際に発火します。
なので、Viewの描画に必要のないプロパティが更新された場合でも、不必要に再描画が走ってしまう等の可能性があります。

Observation では、各プロパティを個別に監視しているため、関係のない値の変更によって不要な更新が走るといったことはありません。

Observationで追加されたマクロ

Observationには@Observableの他に2つのマクロが追加されており、Observableのプロパティに対してアノテーションとして付与することができます。

@ObservationTracked

@ObservationTrackedをプロパティに付与することで、プロパティの変更を検知するようコードを変換します。
が、基本的に開発者が@ObservationTrackedを使うことはありません。
@Observableマクロによって、対象のプロパティを@ObservationTrackedを付与した形にコードを変換してくれるため、開発者が@ObservationTrackedを意識することはないでしょう。

@ObservationIgnored

@ObservationIgnoredをプロパティに付与することで、該当のプロパティを監視しないようコードを変換します。
Observationでは、Combineのように@Publishedを記載しなくてもプロパティの監視ができるようになっている反面、デフォルトで全てのプロパティを監視するようになっているので、監視の必要がない値には@ObservationIgnoredをつけてあげる必要があります。

CounterViewState.swift
import Observation

@Observable final class CounterViewState {
    private(set) var count = 0 // 監視する
    @ObservationIgnored private(set) var title = "" // 監視しない
}

最後に

CombineよりもObservationの違いを見てきましたが、やはりObservationの方が使いやすそうだなといった印象です。
ただ、ObservationはiOS17以降でしか使えないため、既存のアプリに対しては即導入ということはできないので今後に期待です!

また、何かご意見等ありましたらコメントいただけますと幸いです。
どうぞよろしくお願いいたします。

参考

21
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?