@EnvironmentObjectとはどう使う?
📕Overview
A property wrapper type for an observable object that a parent or ancestor view supplies.
親または祖先ビューが提供するobservableオブジェクトのプロパティラッパータイプ。
どのような目的で使うのか、どんな意味なのかというと、違うページで状態を共有することができます。
こちらの動画が参考になりました。
🧷summary
状態をグローバルに扱うことができるDataExampleというクラスを作成します。ObservableObject
というプロトコルに準拠しています。これは呼び出すことで、値を保持している stored propertyを使い、テキストとカウンターの数値をどこのページでも渡すことができます。
もし@State
だったら、ページを作っているstructの中でしか状態を扱えないですね。
VStackに、.で繋げているenvironmentObject
は、Data classであるDataExample
を紐つけています。
TextBlockViewとSampleViewは別Viewでこちらでは、EnvironmentObject
を使って、DataExample
の状態を渡しています。
import SwiftUI
class DataExample : ObservableObject {
var text = "Counter"
var counter = 0
}
struct EnvironmentObjectView: View {
var data = DataExample()
var body: some View {
VStack {
TextBlockView()
SampleView()
}
.environmentObject(data)
}
}
#Preview {
EnvironmentObjectView()
}
TextBlockViewは、図形の中に、EnvironmentObjectを使って、DataExampleの状態を渡しています。
図形をTapすると、onTapGesture
の機能で、counterプロパティの状態が更新されて数字が増えて行きます。他のページでも状態が共有されているので、他のSampleViewでも値は増えていきます。
import SwiftUI
struct TextBlockView: View {
@EnvironmentObject var data : DataExample
var body: some View {
ZStack {
Rectangle()
.frame(width: 200, height: 60)
.foregroundColor(.blue)
.cornerRadius(9)
Text("\(data.text) : \(data.counter)")
.foregroundColor(.white)
}
.onTapGesture {
data.counter += 1
}
}
}
#Preview {
TextBlockView()
}
SampleViewには、ボタンがないので値は増やせないですね。でもTextBlockViewで状態が変更されると、プロパティの値は変化します。状態を監視しているからできるのでしょうね。いや状態が共有されているのか...
import SwiftUI
struct SampleView: View {
@EnvironmentObject var data : DataExample
var body: some View {
Text("\(data.text) : \(data.counter)")
}
}
#Preview {
SampleView()
.environmentObject(DataExample())
}
図形をTapするとこんな感じで別のViewのカウンターも増えていきます。
🧑🎓thoughts
今回は、@EnvironmentObjectを使って違うページで状態を扱うことをやってみました。データにアクセスするが正しいのかもしれない。最近よく使うことが多かったので、SwiftUIの知識のアウトプットのために調べてロジックを書いてみました。
わかりやすくて参考になる日本語の記事もありました。
Discussion