🗽

【SwiftUI】@StateObjectと@ObservedObjectの挙動の違い

2024/09/19に公開

概要

  • StateObjectとObservedObjectの挙動の違いの動作確認を行ったのでメモする

実験1: 挙動の違いを見る

コード

DataSource.swift
class DataSource: ObservableObject {
    @Published var count: Int = 0
}
  • 親view自体に変更が食わられるようにする
ContentView.swift
struct ContentView: View {
    @State private var count = 0

    var body: some View {
        VStack {
            VStack {
                Text("ContentView")
                Text("@state count: \(count)")
                Button("increment") {
                    count += 1
                }
            }

            Spacer().frame(height: 30)
            StateObjectView()
            Spacer().frame(height: 30)
            ObservedObjectView()
        }
        .padding()
    }
}
  • StateObjectを使ったviewと、ObservedObjectを使ったviewを容易
StateObjectView.swift
struct StateObjectView: View {
    @StateObject private var dataSource = DataSource()

    var body: some View {
        VStack {
            Text("StateObjectView")
            Text("dataSource.count: \(dataSource.count)")
            Button("increment") {
                dataSource.count += 1
            }
        }
        .background(Color.mint)
    }
}
ObservedObjectView.swift
struct ObservedObjectView: View {
    @ObservedObject private var dataSource = DataSource()

    var body: some View {
        VStack {
            Text("ObservedObjectView")
            Text("dataSource.count: \(dataSource.count)")
            Button("increment") {
                dataSource.count += 1
            }
        }
        .background(Color.yellow)
    }
}

結果

  • 親viewに更新があったタイミングで、@ObservedObjectの方は初期化される

実験2: @ObservableObjectを活かす

コード

  • 上記のviewを少し改変し、@StateObjectを利用するviewから、その子どものviewの@ObservableObjectにわたす場合を考える
StateObjectView.swift
struct StateObjectView: View {
    @StateObject private var dataSource = DataSource()

    var body: some View {
        VStack {
            Text("StateObjectView")
            Text("dataSource.count: \(dataSource.count)")
            Button("increment") {
                dataSource.count += 1
            }
            ChildObservedObjectView(dataSource: dataSource)
        }
        .background(Color.mint)
    }
}
ChildObservedObjectView.swift
struct ChildObservedObjectView: View {
    @ObservedObject var dataSource: DataSource

    var body: some View {
        VStack {
            Text("ChildObservedObjectView")
            Text("dataSource.count: \(dataSource.count)")
            Button("increment") {
                dataSource.count += 1
            }
        }
        .background(Color.yellow)
    }
}

結果

  • この状況であれば、親viewが更新されてもOK
  • @ObservedObjectは、自身がデータソースとなってはいけないことがわかる

Discussion