【SwiftUI超入門】@EnvironmentObjectの使い方

@EnvironmentObjectとは

@EnvironmentObjectとは@ObservedObjectをそれぞれのViewで共通のプロパティを使えるようにしたものです。

@EnvironmentObjectの使い方は、まず、インスタンスの基となるクラスは『ObservableObject』プロトコルに準拠する必要があります。

変更された時にViewが更新されるようにしたいプロパティには『@Published』を付けます。

class クラス名 : ObservableObject {
    @Published プロパティ
    @Published プロパティ
    …
}

ここまでは@ObservedObjectと同じですね。

違うのはインスタンスの作り方です。

@ObservedObject

@ObservedObject var 変数名 = クラス名()

といったように作りました。

一方で@EnvironmentObjectでは

@EnvironmentObject var 変数名: クラス名

と記述します。

型を指定しているだけなので、クラス名の後には『 ( ) 』は付けません。

また、アプリ全体で使えるようにするためにAppの中で

ContentView()
    .environmentObject(クラス名())

と記述する必要があります。

実際に使ってみる

それでは、実際に使ってみましょう。

SwiftUIのプロジェクトを作成してください。

今回はボタンを押したら年齢が増加するボタンを作って、@ObservedObjectと@EnvironmentObjectでどのような違いがあるのか確かめてみようと思います。

まずは『ContentView.swift』にもう一つViewを作りましょう。

struct AnotherContentView: View {
    var body: some View {
        Text(“AnotherContentVIew”)
    }
}

と記述します。

新しく作ったVIewはContentViewの中に記述します。

その前にContentViewのTextを『VStack』の中に記述しておきましょう。

ContentViewのTextを

『commandボタン』を押した状態でクリックし、『Embed in VStack』をクリックしましょう。

するとTextがVStackで囲われます。

VStackの中にAnotherContentViewを記述しましょう。

Text(“Hello, World!”)の下に

AnotherContentView()

と記述しましょう。

Previewを見てみると、ContentVIewの中にAnotherViewが表示されていますね。

次にObservableObjectプロトコルに準拠したクラスを作りましょう。

新しくファイルを作ります。

『File > New > File…』と押していきましょう。

『SwiftUI VIew』を選択し、

『Next』を押します。

するとファイル名が聞かれるので『UserData』と入力し、

『Create』ボタンを押しましょう。

これで『UserData.swift』というファイルが新しく出来上がります。

このファイルにObservableObjectに準拠したクラスを記述しましょう。

import SwiftUI以外の記述を

class UserData: ObservableObject {
    @Published var name = “田中”
    @Published var age = 25
}

と書き換えましょう。

このクラスを使って@ObservedObjectと@EnvironmentObjectを使ったインスタンスをそれぞれ作っていきます。

@ObservedObject

まずは、『ContentView』と

『AnotherContentView』に

それぞれ@ObservedObjectを使ったインスタンスを作りましょう。

『ContentView.swift』の

@ObservedObject var userData = UserData()

と記述しましょう。

AnotherContentViewにも

同じように

@ObservedObject var userData = UserData()

と記述しましょう。

@ObservedObjectを付けた場合、インスタンスはそれぞれのViewで独立した値をとります。

ContentViewとAnotherContentViewでuserDataを使い、ボタンを押して値を変更した時に片方だけ変更されるのか確かめてみようと思います。

まずは、AnotherContentViewでuserDataのプロパティをテキストに埋め込んでみましょう。

『Text(“AnotherContentVIew”)』を

Text(“AnotheContentView: \(userData.name)の年齢は\(userData.age)”)

と書き換えましょう。

ContentViewでも同じようuserDataのプロパティをテキストに埋め込んでみましょう。

『Text(“Hello, world!)』を

Text(“ContentView: \(userData.name)の年齢は\(userData.age)”)

と書き換えます。

Previewを見てみると、このような表示になっていますね。

この状態で年齢が増えるボタンをContentViewに記述してみましょう。

Button(action: {
    userData.age += 1
})
{
    Text(“年齢を増やす”)
}

と記述します。

『Live Previewボタン』を押し、

『年齢を増やすボタン』を押すと、

AnotherContentViewの方は増えず、ContentViewの方だけ増えます。

これは@ObservedObjectを使って作ったインスタンスのプロパティはそれぞれのViewで独立しているからです。

@EnvironmentObject

共通の値を使いたい時は@EnvironmentObjectを使ってインスタンスを作ります。

ContentViewとAnotherContentViewの@ObservedObjectをそれぞれ@EnvironmentObjectで書き換えてみましょう。

まずはContentViewの@ObservedObjectを使っている部分を

@EnvironmentObject var userData: UserData

と書き換えましょう。

同じようにAnotherContentViewの方も

@EnvironmentObject var userData: UserData

と書き換えておきましょう。

次に『ContentView_Previews』の

『ContentView()』に

.environmentObject(UserData())

と追加しましょう。

これでContentViewでUserDataクラスをenvironmentObjectとして使うことができるようになりました。

この状態で『Live Preview』ボタンを押し、

『年齢を増やすボタン』を押してみましょう。

すると、今度は『ContentView』、『AnotherContentVIew』どちらも年齢が増えていますね。

このように、@EnvironmentObjectを使うと共通のプロパティを使うことができます。

ContentView_PreviewsのContentView()に『.environmentObject(UserData())』を付け足した場合、Previewでは@EnvironmentObjectを使うことができるのですが、シミュレータや実機では使うことができません

シミュレータや実機で使えるようにするには『EnvironmentObjectSwiftUIApp.swift』の

『ContentView()』に

.environmentObject(UserData())

と追加しましょう。

これで、シミュレータや実機であっても@EnvironmentObjectを使えます。