【Swift】Observation基本の基。

## はじめに
WWDC23で発表された新たなフレームワークのObservationの使い方を少しばかり勉強したのでアウトプットです。
今までのCombineとどのようにコードが変わるかを紹介していきます。

## この記事でわかること
- Observationってどんなものか
- Observationを使ってとりあえずプログラムを動かす方法
- Combineと比較して何が変わったのか

## 想定読者
- SwiftUI触ったことあるよーという人
- ObservableObject使ったことあるよーという人

## この記事で説明していないこと
- UIKitとObservationを合わせてどう使うかについて
- ```@Bindable```などのプロパティラッパーについて

## Observationって？
- WWDC23で発表された新たなフレームワークです
- Combineの進化系。みたいなイメージでいいと思いいます
- iOS17からのみ使用可能です

## 今回作るサンプル
- とてもシンプルなサンプルです。「add peach」ボタンタップするとリストに「もも」が追加されていきます。このサンプルを使って`Observation`の使い方を`Combine`と比較しながら紹介します。ぜんぜん関係ないですが、「シンプルなサンプル」って韻踏んでていいっすね。

![Simulator Screen Recording - iPhone 15 - 2024-02-08 at 17.44.06.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2644705/b15b08d2-d162-df68-9d7b-3c7804f59696.gif)

## Combineを使った書き方
まずはCombineフレームワークに含まれる```ObservableObject```を使った書き方です

### ViewModelのコード

```Swift
import Combine

final class ObservableObjectFruitViewModel: ObservableObject {

    @Published var fruits = ["りんご", "ばなな", "みかん", "ぶどう", "さくらんぼ"]

    func tappedAddPeachButton() {
        fruits.append("もも")
    }
}
```

### 特徴
- クラスに`ObservableObject`プロトコルを準拠させます
- 監視したいプロパティに`@Published`を付与します
- 監視したいプロパティが複数あれば、全てに`@Published`を付与する必要があります

### Viewのコード

```Swift

import SwiftUI

struct ContentView: View {

    @StateObject private var viewModel = ObservableObjectFruitViewModel()

    ~~ 省略 ~~
}

```

### 特徴
- viewModelのプロパティに`@StateObject`を付与

上記のように書くことで、viewModelの`fruits`が監視され、変更が加わるとViewに自動的に反映されます。
では次に`Observation`だとどのように書くことができるか紹介します。

## Observationを使った書き方

### ViewModelのコード

```Swift
import Observation

@Observable
final class ObservationFruitViewModel {

    var fruits = ["りんご", "ばなな", "みかん", "ぶどう", "さくらんぼ"]

    func tappedAddPeachButton() {
        fruits.append("もも")
    }
}

```
### 特徴
- クラスに`@Observable`マクロを付与します
- `@Observable`マクロを付与したクラスのプロパティは全て監視対象になります

### Viewのコード

```Swift
struct ContentView: View {

    @State private var viewModel = ObservationFruitViewModel()

   ~~ 省略 ~~
}

```

### 特徴
- viewModelプロパティに`@State`を付与します。

上記のようにViewModelクラスには`@Observable`マクロを付与し、View側のviewModelプロパティに`@State`を付与することで、値を監視し、`fruits`プロパティが変更されるとViewに反映されます。

## ViewModelのプロパティを監視から外したい場合

### Combine

`@Published`を削除すれば監視対象から外れます。

```Swift
final class ObservableObjectFruitViewModel: ObservableObject {

    /* @Published */var fruits = ["りんご", "ばなな", "みかん", "ぶどう", "さくらんぼ"]

    func tappedAddPeachButton() {
        fruits.append("もも")
    }
}
```

### Observation

`@ObservationIgnored`を付与すれば監視対象から外れます。

```Swift
@Observable
final class ObservationFruitViewModel {

    @ObservationIgnored ← これをつける
    var fruits = ["りんご", "ばなな", "みかん", "ぶどう", "さくらんぼ"]

    func tappedAddPeachButton() {
        fruits.append("もも")
    }
}
```
上記のように監視対象から外せば、ボタンをタップしてもリストは変化しません

## Observationのうれしいところ
Observationを使用することで、ViewModelで監視対象にするプロパティ全てにいちいち`@Published`を付与していく必要がないというのは楽ですね。付与し忘れるということも無くなりそうです。

それに加えてこの記事では詳しく書きませんが、`@Binding`を使用した子Viewの更新にも差があります。
Observationを使用することで、変更があった子Viewのみを再描画するようになりました。これに関してはまたどこかで。

## サンプルのViewのコード全体
- Observationを使った実装のViewのコードです。Combineを使っている場合はViewModelのクラスが変わります。
```Swift
import SwiftUI

struct ContentView: View {

    @State private var viewModel = ObservationFruitViewModel()

    var body: some View {
        VStack {

            Button("add peach") {
                viewModel.tappedAddPeachButton()
            }
            .padding(.vertical, 24)

            List(viewModel.fruits, id: \.self) { item in
                Text(item)
            }
        }
    }
}
```

## 今回のサンプル
https://github.com/Rin-t/PracticeObservation


## おわりに
WWDC23ではCombineについての発表もなかったみたいなので、今後はObservationの時代になっていきそうですね。
ではでは！！

## 参考
https://techbookfest.org/product/vFjd8cyB0ic0v2a7EECm7u?productVariantID=ksMDDE6xtziytRnpYahstU