SwiftUI を使うには基本で必須です。
@State と @Binding。
どう書いてますか。
親 View があるとして 子 View でどう受けるか。
struct ParentView: View {
@State private var text: String = ""
var body: some View {
VStack {
TextField("Parent", text: $text)
Text(text)
Divider()
ChildView(text: $text)
}
.padding()
}
}
struct ChildView: View {
var body: some View {
TextField()
Text()
}
}
こういうイメージです。
きちんと Binding されていますね。
ChildView をシンプルに書いてみます。
あくまで受け渡し記述の確認です。
🤔 あれこれやってみる
他言語からきて、まずは書きそうなこれ。
イニシャライザ経由で型を合わせて渡します。
wrappedValue も直感的に分かるでしょう。
struct ChildView: View {
private var text: Binding<String>
init(text: Binding<String>) {
self.text = text
}
var body: some View {
TextField("Child", text: text)
Text(text.wrappedValue)
}
}
→ OK
次は、イニシャライザーを使わずに、プロパティを露出させます。
struct ChildView: View {
var text: Binding<String>
var body: some View {
TextField("Child", text: text)
Text(text.wrappedValue)
}
}
→ OK
次は、マクロを使います。
@State で受けると、参照が切れます。新規に作成するんですね。
struct ChildView: View {
@State private var text: String
init(text: Binding<String>) {
self.text = text.wrappedValue
}
var body: some View {
TextField("Child", text: $text)
Text(text)
}
}
→ NG
次は、何も分かってないのに @Binding を使います。
struct ChildView: View {
@Binding private var text: String
init(text: Binding<String>) {
self.text.projectedValue = text // NG
}
var body: some View {
TextField("Child", text: $text)
Text(text)
}
}
Referencing property 'projectedValue' requires wrapper 'Binding<String>'
→ NG
次は、少しネットで調べて、一番多く目についた書き方。
_ (アンダースコア) が強烈な違和感ですが、問題なく動きます。
struct ChildView: View {
@Binding private var text: String
init(text: Binding<String>) {
_text = text
}
var body: some View {
TextField("Child", text: $text)
Text(text)
}
}
→ OK
次は、public にして、イニシャライザー省略。
struct ChildView: View {
@Binding var text: String
var body: some View {
TextField("Child", text: $text)
Text(text)
}
}
→ OK
🤔 まとめ
これが一番簡潔に書けるんですね!
struct ChildView: View {
@Binding var text: String
var body: some View {
TextField("Child", text: $text)
Text(text)
}
}
子ではプロパティのアクセス修飾子を public のイニシャライザー省略で受ける。
どうやら、この
@Binding var text: String
は、
private var _text: Binding<String>
private var text: String {
get {
_text.wrappedValue
}
set {
_text.wrappedValue = newValue
}
}
init(text: Binding<String>) {
_text = text
}
と等価のようにみえます。
あと、孫 View に渡すには、@Binding から @Binding できますね!
※ 後で知ったのですが、public や private などのアクセスレベルの省略は「internal」扱いでした !
最後に、Playground コードを貼っておきます。
Jetpack Compose から SwiftUI に来ましたが今の謎をどうにかしたい 😩#jetpackcompose #swiftui #プログラミング初心者 https://t.co/Ojrd7C1rWq
— chanzmao (@maochanz) December 21, 2023
👉 【SwiftUI】再描画の伝播 - @State と @Binding
関連ワード: apple・iOS・iPhone・mac・macOS・Swift・今さら聞けない・初心者・開発・SwiftData・SwiftUI