SwiftUIの「$」って何ですか?
$ってなに
よくこのようにTextFieldなどで、stateプロパティに「\$」をつけたものを渡します。
「$」をつけると値の変更を検知してプロパティを更新してくれるようなる
と何となく理解していましたが、理解が不十分なので調べてみました。
@State private var text1 = ""
var body: some View {
TextField("text1", text: $text1)
}
公式ドキュメントを読んでみる
まずは公式ドキュメントに何か書いてないかと思い
Stateのドキュメントを確認してみました。
To pass a state property to another view in the view hierarchy, use the variable name with the \$ prefix operator. This retrieves a binding of the state property from its projectedValue property.
Viewの階層下にある他のViewにstateプロパティを渡すには、「$」を変数の先頭つけて使う。
これはそのprojectedValueからstateプロパティのbindingを取得する。
太文字部分が「$」をつけてできることを示していることはわかりましたが
またわからないことが出てきました。
- projectedValueってなに
A binding to the state value.
StateのprojectedValueを一言で表すと
"state valueへのbinding" のようです。
getterプロパティとして用意されています。
var projectedValue: Binding<Value> { get }
- Bindingってなに
A property wrapper type that can read and write a value owned by a source of truth.
一言で表すと "信頼できる一つの情報源に所有された値を読み書きできるプロパティラッパータイプ" のようです。
難しいのでもう少し読んでみます。
Use a binding to create a two-way connection between a property that stores data, and a view that displays and changes the data
データを格納するプロパティとViewを表示したり更新したりするデータの間の双方向接続を作るためにbindingを使用する
BindingがプロパティとUIの双方向の接続のためのものであることがわかりました。
つまり
「\$」をつけるとprojectedValueというgetterプロパティへアクセスすることになる。
Stateで定義したプロパティのprojectedプロパティは
stateプロパティのbindingを取得することになるので
今回の例の場合 $text は Binding<String> を表しています。
TextFieldで実際に確認してみた
TextFieldを使って確認していきます。
TextFieldの第二引数にはBinding<String>を渡さなければいけないため
stateプロパティをそのまま渡すとエラーになります。
TextFieldはユーザーの入力を受け付けるので
入力された値とプロパティの値が同期されるように
Bindingでラップした値を入れる必要があるのは理解できますね。
@ObservedObject
の@Published
プロパティの場合どうなる?
もう少し深掘りしていきます。
今度は@ObservedObject
の@Published
の値をTextFieldに渡す場合に
どこに「\$」を付けるべきなのかを確認していきます。
4つの選択肢のうちどれが正解でしょうか?
$model.text - ①
$model.$text - ②
model.$text - ③
model.text - ④
私は@Published
のprojectedValueが 値をBindingでラップした値を返すと考え
それがBindingになると思ったので③model.$textかなと思いましたが違っていました。
正解は①$model.textでした。
他の選択肢はエラーが出たので確認していきます。
③model.$text
予想していたこれからみていきます。
Cannot convert value of type 'Published.Publisher' to expected argument type 'Binding'
'Binding'ではなく'Published.Publisher'になっているようです。
公式ドキュメント確認すると
@Published
のprojectedValueはPublished<Value>.Publisher
でした。
そのため model.$text は Published.Publisher を表しており、不正解です。
②$model.$text
Cannot convert value of type 'Binding.Publisher' to expected argument type 'Binding'
'Binding.Publisher'になっています。
@ObservedObject
のprojectedValueを確認すると
ObservedObject<ObjectType>.Wrapper
になっていましたがパッとみてわかりません。
説明文を読むとこうありました。
A projection of the observed object that creates bindings to its properties using dynamic member lookup.
理解しづらいですが私は
保持しているプロパティのBindingを動的に生成する監視オブジェクトの投影
つまり
複数のプロパティを持つBindingだと飲み込みました。
そのため \$model.$text は Binding<Published.Publisher> を表しており、不正解です。
④model.text
これは単純にStringを表しているので不正解です。
@ObservedObject
をネストさせたら・・・
さらに@ObservedObject
の中に@ObservedObject
を入れてみたらこの2通りがエラーになりませんでした。
TextField("text", text: $model.model.text)
TextField("text", text: model.$model.text)
ただビルドして入力してみるとこのようなwarningが出ました。
Binding action tried to update multiple times per frame.
おそらく上記のような使い方はしないほうがよさそうです。
これに関しては別記事にしたいと思います。
次に記事にしたいこと
- ObservedObjectをネストした場合の「$」の使い方
- SwiftUIの「@」って何ですか?
Author And Source
この問題について(SwiftUIの「$」って何ですか?), 我々は、より多くの情報をここで見つけました https://qiita.com/yuskey/items/815af3f7201ecc8dd0f7著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .