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
}
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」扱いでした !
【Swift】「public」 を省略しない理由
最後に、Playground コードを貼っておきます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI
import PlaygroundSupport
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 {
// private var text: Binding<String>
//
// init(text: Binding<String>) {
// self.text = text
// }
//
// var body: some View {
// TextField("Child", text: text)
// Text(text.wrappedValue)
// }
//}
//struct ChildView: View {
// var text: Binding<String>
//
// var body: some View {
// TextField("Child", text: text)
// Text(text.wrappedValue)
// }
//}
// NG
//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)
// }
//}
// NG
//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)
// }
//}
// 主流?
//struct ChildView: View {
// @Binding private var text: String
//
// init(text: Binding<String>) {
// _text = text
// }
//
// var body: some View {
// TextField("Child", text: $text)
// Text(text)
// }
//}
struct ChildView: View {
@Binding var text: String
var body: some View {
TextField("Child", text: $text)
Text(text)
}
}
PlaygroundPage.current.setLiveView(
ParentView()
.frame(width: 300, height: 300)
)
【SwiftUI】再描画の伝播 - @State と @Binding