🌐

[SwiftUI]@EnvironmentObjectの使用方法とハマりどころ

2022/01/21に公開

はじめに

EnvironmentObjectを始めて使用する際に結構な確率でハマる部分があります。
そのハマり箇所も含めて簡単にまとめてみました。

環境

・ macOS: Monterey
・ Xcode: 13.2

EnvironmentObjectの使用方法

EnvironmentObjectはSwiftUIのデータバインディングの仕組みの一つでアプリ内でデータを共有したい場合に使用します。
また使用する際、インスタンスの基となるクラスは"ObservableObject"プロトコルに準拠する必要があり、更新したデータを受け取るにはプロパティに"@Published"を付けます。
使用例としてはViewの監視をViewModelで行うのでViewModel側のプロトコルを"ObservableObject"に準拠させて使用する方法が多いかと思います。
使用例を参考に深めていただけると幸いです。

使用例

使用例ではTestViewModelというクラスにtestFlagというBool型のプロパティを持たせて、TestView1とでデータを更新した場合TestView2でも反映されるものを紹介します。

TestViewModel
class TestViewModel: ObservableObject {
    @Published var testFlag = false
}
TestView1
struct TestView1: View {
    @EnvironmentObject var testViewModel: TestViewModel
    var body: some View {
        VStack{
            Toggle(isOn: $testViewModel.testFlag) {
                Text("TestView1")
            }
            Text(testViewModel.testFlag ? "true" : "false")
        }
    }
}
TestView2
struct TestView2: View {
    @EnvironmentObject var testViewModel: TestViewModel
    var body: some View {
        VStack{
            Toggle(isOn: $testViewModel.testFlag) {
                Text("TestView2")
            }
            Text(testViewModel.testFlag ? "true" : "false")
        }
    }
}
TestView
struct TestView: View {
    @EnvironmentObject var testViewModel: TestViewModel
    var body: some View {
        VStack{
            TestView1()
            TestView2()
        }
        .environmentObject(testViewModel)
    }
}

これでTestViewのプレビューをみると以下の動作が確認できます。

動画よりTestView1とTestView2でインスタンス化したtestViewModelですが、それぞれのView内でデータを更新しているにも関わらず、他のViewでもリアルタイムで更新されている事が確認できます。

プレビューのエラー(ハマりどころ)

@EnvironmentObjectを使用したViewをプレビューで表示させたい場合必ずenvironmentObjectを付けないとエラーになります。
上記のTestViewを例に、プレビューをする時は以下のようにenvironmentObjectを付ける。

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        TestView()
            .environmentObject(TestViewModel())
    }
}

まとめ

誰かの役に立てばうれしいです。

Discussion