【SwiftUI】@ObservedObjectの使い方を徹底解説

この記事では、@ObservedObjectの使い方を解説していきたいと思います。

ObservedObjectオブザードオブジェクトとは?

簡単に言うと、@ObservedObjectとは、@Stateを複数同時に宣言できるクラスのことです。

@Stateの場合は、Viewごとに変数を宣言して使いますが、@ObservedObjectはクラスなので複数の変数をまとめて宣言して、複数のViewから使うことができます。

厳密にはちょっと違いますが、イメージ的にはこんな感じです。

使い方

使い方としては、ObservableObjectを準拠させたclass内に、@Stateの代わりに@Publishedを定義して、使いたいViewで@ObservedObjectで宣言して使います。

ちょっとややこしいので、サンプルコードを見ながら解説していきます。

以下のコードが@ObservedObjectを使ったサンプルコードです。

import SwiftUI

class Fruits: ObservableObject {
    @Published var name = "りんご"
    @Published var price = 100
}

struct ContentView: View {
    @ObservedObject var fruits = Fruits()
    
    var body: some View {
        VStack {
            Text("\(fruits.name)一個\(fruits.price)円です")
                .padding()
            Button("10円値上げする") {
                fruits.price += 10
            }
        }
    }
}
コード解説

まず、FruitsというObservableObjectプロトコルに準拠したclassを定義します。

その中に、@Publishedをつけて変数を宣言します。@Publishedは@Stateと同じようなものだと思ってください。

そして、使いたいViewで@ObservedObjectをつけてfruitsという名前でインスタンス化します。

インスタンス化したら、fruits.nameや、fruits.priceと言うふうに@Stateと同じく使えます。値の更新をすると@Stateと同じく再描画されすぐに画面に反映されます。

別のViewと共有する

まとめて共有する

@Stateの場合は、@Bindingで渡していましたが、@ObservedObjectの場合は、インスタンスで渡してあげると全てのデータまとめて渡すことができます。

以下のコードは、BViewでfruitsの名前を変更するサンプルコードです。

class Fruits: ObservableObject {
    @Published var name = "りんご"
    @Published var price = 100
}

struct ContentView: View {
    @ObservedObject var fruits = Fruits()
    @State var isShowBView = false
    
    var body: some View {
        VStack {
            Text("\(fruits.name)一個\(fruits.price)円です")
                .padding()
            Button("10円値上げする") {
                fruits.price += 10
            }
            .padding()
            Button("BViewへ遷移") {
                isShowBView = true
            }
        }
        .sheet(isPresented: $isShowBView) {
            BView(fruits: fruits)
        }
    }
}

struct BView: View {
    @ObservedObject var fruits: Fruits
    
    var body: some View {
        Button("みかんに変える") {
            fruits.name = "みかん"
        }
    }
}
コード解説

BViewで、@ObservedObject var fruits: Fruitsというように書くことで、@Bindingのように、ContentViewのfruitsと紐づけることができます。

一部分だけ共有する

@Stateと同じく1つの値なら、@Bindingでも渡すことができます。挙動的には上記と全く変わりません。

class Fruits: ObservableObject {
    @Published var name = "りんご"
    @Published var price = 100
}

struct ContentView: View {
    @ObservedObject var fruits = Fruits()
    @State var isShowBView = false
    
    var body: some View {
        VStack {
            Text("\(fruits.name)一個\(fruits.price)円です")
                .padding()
            Button("10円値上げする") {
                fruits.price += 10
            }
            .padding()
            Button("BViewへ遷移") {
                isShowBView = true
            }
        }
        .sheet(isPresented: $isShowBView) {
            BView(fruitsName: $fruits.name)
        }
    }
}

struct BView: View {
    @Binding var fruitsName: String
    
    var body: some View {
        Button("みかんに変える") {
            fruitsName = "みかん"
        }
    }
}

まとめ

まとめると、@ObservedObjectというのは、@Published(@Stateのようなもの)をまとめたクラスです。使うときはインスタンス化して使います。