@Observable @State @Binding @Bindable 付ける付けない調査隊
毎年仕様が変わるので毎年やってますなw
機械的に付ける付けないをいろんなパターン試して挙動を調査するものです。
意味がない組み合わせがあっても気にしません。
やること
モデルを親Viewで作って子Viewに渡す。
イメージ図
モデル
@Observable
class Book {
var title = String(Int.random(in: 0...100000))
}
@Observable
を付ける付けないの2通り試します。
今回は class のみやります。
親View
struct ObservationTest1: View {
@State var book = Book()
var body: some View {
Button {
book = Book()
} label: {
Text("New")
}
Button {
book.title = String(Int.random(in: 0...100000))
} label: {
Text("Change")
}
Text(book.title)
//ObservationTest2(book: book)
//ObservationTest3(book: $book)
ObservationTest4(book: book)
}
book
に @State
を付ける付けないの2通り試します。
@State
を付ける場合は
- Newボタンあり
@State
を付けない場合は
- Newボタンなし(変更不可のエラーが出るのでなし)
共通して
- book.titleを表示する
- 子Viewを呼ぶ
子View
var book: Book
が定義してあるObservationTest2。
@Binding var book: Book
が定義してあるObservationTest3。
@Bindable var book: Book
が定義してあるObservationTest4。
ObservationTest2
struct ObservationTest2: View {
var book: Book
var body: some View {
Button {
book.title = String(Int.random(in: 0...100000))
} label: {
Text("Change")
}
Text(book.title)
}
ObservationTest2は
- book.titleを変更するボタンがある
- book.titleを表示する
ObservationTest3
struct ObservationTest3: View {
@Binding var book: Book
var body: some View {
Button {
book = Book()
} label: {
Text("New")
}
Button {
book.title = String(Int.random(in: 0...100000))
} label: {
Text("Change")
}
Text(book.title)
}
ObservationTest3は
- bookを変更するボタンがある
- book.titleを変更するボタンがある
- book.titleを表示する
ObservationTest4
struct ObservationTest4: View {
@Bindable var book: Book
var body: some View {
Button {
book.title = String(Int.random(in: 0...100000))
} label: {
Text("Change")
}
Text(book.title)
}
}
ObservationTest4は
- book.titleを変更するボタンがある
- book.titleを表示する
book
への再代入は出来ないので、book
の変更はありません。
@Observableなし @Stateなし @Bind〜なし
親で titleを 更新すると |
子で titleを 更新すると |
|
---|---|---|
親Viewの Text(book.title)は |
更新なし | 更新なし |
子Viewの Text(book.title)は |
更新なし | 更新なし |
@Observableなし @Stateなし @Bindingあり
エラー
渡せない
@Observableなし @Stateなし @Bindableあり
エラー
@Bindable
が @Observable
を要求
@Observableなし @Stateあり @Bind〜なし
親で bookを 新規作成すると |
親で titleを 更新すると |
子で titleを 更新すると |
|
---|---|---|---|
親Viewの Text(book.title)は |
更新 | 更新なし | 更新なし |
子Viewの Text(book.title)は |
更新 | 更新なし | 更新なし |
親のbody再構築 |
@Observableなし @Stateあり @Bindingあり
親で bookを 新規作成すると |
親で titleを 更新すると |
子で bookを 新規作成すると |
子で titleを 更新すると |
|
---|---|---|---|---|
親Viewの Text(book.title)は |
更新 | 更新なし | 更新 | 更新なし |
子Viewの Text(book.title)は |
更新 | 更新なし | 更新 | 更新なし |
親のbody再構築? | 親のbody再構築? |
@Observableなし @Stateあり @Bindableあり
エラー
@Bindable
が @Observable
を要求
@Observableあり @Stateなし @Bind〜なし
親で titleを 更新すると |
子で titleを 更新すると |
|
---|---|---|
親Viewの Text(book.title)は |
更新 | 更新 |
親Viewの Text(book.title)は |
更新 | 更新 |
@Observableあり @Stateなし @Bindingあり
エラー
渡せない
@Observableあり @Stateなし @Bindableあり
親で titleを 更新すると |
子で titleを 更新すると |
|
---|---|---|
親Viewの Text(book.title)は |
更新 | 更新 |
子Viewの Text(book.title)は |
更新 | 更新 |
@Observableあり @Stateあり @Bind〜なし
親で bookを 新規作成すると |
親で titleを 更新すると |
子で titleを 更新すると |
|
---|---|---|---|
親Viewの Text(book.title)は |
更新 | 更新 | 更新 |
子Viewの Text(book.title)は |
更新 | 更新 | 更新 |
親のbody再構築 |
@Observableあり @Stateあり @Bindingあり
親で bookを 新規作成すると |
親で titleを 更新すると |
子で bookを 新規作成すると |
子で titleを 更新すると |
|
---|---|---|---|---|
親Viewの Text(book.title)は |
更新 | 更新 | 更新 | 更新 |
子Viewの Text(book.title)は |
更新 | 更新 | 更新 | 更新 |
親のbody再構築? | 親のbody再構築? |
@Observableあり @Stateあり @Bindableあり
親で bookを 新規作成すると |
親で titleを 更新すると |
子で titleを 更新すると |
|
---|---|---|---|
親Viewの Text(book.title)は |
更新 | 更新 | 更新 |
子Viewの Text(book.title)は |
更新 | 更新 | 更新 |
親のbody再構築? |
@State @Bindable が必要な理由
@Observable
にすると title
の変更に反応するので上の調査では @State
や @Bindable
は要らないように見えるが、@State
や @Bindable
はさらに下にBindingで渡すときに必要になる。
struct BookEditView: View {
@Bindable var book: Book
@Environment(\.dismiss) private var dismiss
var body: some View {
VStack() {
HStack {
Text("Title")
TextField("Title", text: $book.title) //ここで必要
.textFieldStyle(.roundedBorder)
.onSubmit {
dismiss()
}
}
Button("Close") {
dismiss()
}
.buttonStyle(.borderedProminent)
}
.padding()
}
}
考察
上の調査では
@Observable
あり @State
あり @Binding
ありと
@Observable
あり @State
あり @Bindable
ありは、
インスタンスを新しく作成すること以外は一緒の結果。@Bindable
は再代入しようとするとエラーが出る。これはわざとか?
@Binding
よりも @Bindable
が良い点としては @Observable
の付け忘れでエラーが出る点がある。
@Observable
なし @State
あり @Binding
ありはエラーが出ず、title
を変更してもViewが更新されない。
@Observable
なし @State
あり @Bindable
ありはエラーになる。@Bindable
が @Observable
を要求するので。
さいごに
Observationの学習中に書いたもので理解が不十分かもしれません。何か指摘がある場合はよろしくお願いします。
Discussion