Sponsor Link
@State は struct にしか使えない
@State は、struct (というか、value-type) にしか使えないんです。
見てみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
struct IntValueStruct { // (1) var intValue:Int = 0 } struct ContentView: View { @State private var stateValue:IntValueStruct = IntValueStruct() var body: some View { VStack { Spacer() Text("stored value: \(stateValue.intValue)") Stepper("value \(stateValue.intValue)", value: $stateValue.intValue) Button(action: {print("\(stateValue.intValue)")}, label: {Text("check stateValue")}) Spacer() } .padding() } } |
(1) で、@State の対象は、struct として定義しています。
class に変えてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class IntValueClass { // (1) class に変えました var intValue:Int = 0 } struct ContentView: View { @State private var stateClassValue:IntValueClass = IntValueClass() var body: some View { VStack { Spacer() Text("stored value: \(stateClassValue.intValue)") Stepper("value \(stateClassValue.intValue)", value: $stateClassValue.intValue) Button(action: {print("\(stateClassValue.intValue)")}, label: {Text("check Value")}) Spacer() } .padding() } } |
“Check Value” ボタンでその時点での値を、Xcode のコンソールに出力することができます。出力してみると Stepper の + ボタンを押した数分増えた数値が、コンソールに表示されることが確認できます。ですので、値が変更されていないのではなく、ビューが更新されていないと確認できます。
つまり、@State は、class に対して使用すると、@Binding と組み合わせることで、値のリファレンスを渡すことはできていますが、その変更をフェッチし、ビューを更新することができていない ことがわかります。
まさしく、このケースが、@ObservedObject を使うケースとなります。
@ObservedObject
@ObservedObject の property wrapper を付与するためには、class が ObservableObject を conform していなければなりません。
@ObservedObject を使ったものを追記すると以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class IntValueClass :ObservableObject { // ObservableObject に 準拠 @Published var intValue:Int = 0 // @Published で変更を検知するプロパティを設定 } struct ContentView: View { @ObservedObject var obsClassValue:IntValueClass = IntValueClass() var body: some View { VStack { Spacer() Text("stored value: \(obsClassValue.intValue)") Stepper("value \(obsClassValue.intValue)", value: $obsClassValue.intValue) Spacer() } .padding() } } |
実行してもらうとわかりますが、下側の UI は、期待通りに動作します。
ObservableObject とは? @Published とは?
ObservableObject とは、内部にobjectWillChange というプロパティを持つことを要求する Protocol です。objectWillChange のタイプは、Publisher です。
Apple のドキュメントは、こちら。
@Published は、そのプロパティの変更について、上記の Publisher を使って、通知します。
まとめ
設定対象 | |
@State | struct, enum |
@ObserervedObject | class |
- @ObservedObject として使用される class は、ObservableObject プロトコルに準拠するように定義されなければいけない
- 変更を監視するプロパティに、@Published を付与する
- @ObservedObject に含まれる @Published が付与されているプロパティは、@Binding で受ける
説明は以上です。
不明な点やおかしな点ありましたら、ご連絡いただけるとありがたいです。
Sponsor Link