【SwiftUI】ObservedObjectの中に入れたクラスの変更でViewを更新したい時の注意

ObservedObjectの中にデータクラスを入れてその更新を取得しようとしたらハマったので共有
どうやらこのケースはこのままだとViewが更新されない模様
（もし間違っていたりこんなやり方もあるよーというのがあれば対応いたしますので教えていただければ幸いです！）

#実験
1秒に1ずつ増えていくsubCountを持つDataClassを作成

```swift:DataClass
class DataClass: ObservableObject {
    @Published var subCount = 0
    var timer = Timer()

    init(){
        //生成と共にタイマー開始
        timer =  Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(classLoop), userInfo: nil, repeats: true)
    }
    // タイマーで呼び出されるメソッド
    @objc func classLoop() {
        subCount = subCount + 1
    }
}
```

　
5秒に1ずつ増えていくrootCountと先程のDataClassを持つPublishTestも作ります

```swift:DataClassを持つPublishTest
class PublishTest: ObservableObject {
    @Published var rootCount: Int = 0
    @Published var dataclass = DataClass()
    
    var timer = Timer()

    init(){
        //生成と共にタイマー開始
        timer =  Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(classLoop), userInfo: nil, repeats: true)
        }
    }
    // タイマーで呼び出されるメソッド
    @objc func classLoop() {
        rootCount = rootCount + 1
    }
}
```


最後にView側は下記を表示させます

* publishTest自身のrootCount
* publishTestが持つDataClassのsubCount

```swift:View側
struct ContentView: View {
    
    @ObservedObject var publishTest: PublishTest
    
    var body: some View {
        VStack{
            Text("rootCountは\(publishTest.rootCount)")
            Text("DataClassのsubCountは\(publishTest.dataclass.subCount)")
        }
    }
}
```

#結果
![スクリーンショット 2021-07-06 16.23.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507462/de3d1808-c067-a2f4-6815-98f035b86f16.png)

しばらく更新されません
尚、printでログ表示するとsubCountが増えているのを確認できます

![スクリーンショット 2021-07-06 16.23.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507462/434882dc-c884-48c8-a734-9c8ceb7821fe.png)
5秒経ち、rootCountが更新されるとrootCountもsubCountもその時点のものに更新されます

何もしない場合、下記の挙動になるようです

* ObservedObjectの中に入れ子にしたサブクラス側の変更はView側に伝わない
* ObservedObject直下の何かしらが更新された時にViewが更新されサブクラスのデータも反映

#対応策
###　1.ObservedObject直下のデータを利用する構造にする
身も蓋もないですが、View側で更新させたいものは全てObservedObject直下のものだけを使う構造にするのが1つ。
もしくは更新させたいタイミングでObservedObjectのデータを強制的に更新する事でも実現は可能かもしれません（上記の実験のケース）

###　2. CombineのobjectWillChangeを利用する

CombineのobjectWillChangeを利用する事でデータの更新が反映されるみたいです。
こちらの記事が参考になりました
https://www.it-swarm-ja.com/ja/ios/%E5%85%A5%E3%82%8C%E5%AD%90%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9Fobservableobject%E3%81%AB%E3%83%90%E3%82%A4%E3%83%B3%E3%83%89%E3%81%99%E3%82%8B%E3%82%88%E3%81%86%E3%81%ABswiftui%E3%83%93%E3%83%A5%E3%83%BC%E3%81%AB%E6%8C%87%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/813692063/

PublishTest側に追加してみます

```swift:DataClassを持つPublishTest(更新)
import Combine

class PublishTest: ObservableObject {
    @Published var rootCount: Int = 0
    @Published var dataclass = DataClass()
    var timer = Timer()

    var anyCancellable: AnyCancellable? = nil   //追加


    init(){
        timer =  Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(classLoop), userInfo: nil, repeats: true)
        
        //追加ここから
        anyCancellable = dataclass.objectWillChange.sink { (_) in
            self.objectWillChange.send()
        }
        //追加ここまで
    }

    // タイマーで呼び出されるメソッド
    @objc func classLoop() {
        rootCount = rootCount + 1
    }
}
```

これで更新されている事を確認
![スクリーンショット 2021-07-06 16.52.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507462/9bf96dd9-6cc3-d880-467f-2251489fece5.png)