はじめに
前回、private
な変数・定数が含まれるclassやstructをMemberwise Initializerで初期化しようとするとエラーが起きることを知りました。今回は、自分でinit
を作成する際に@Binding
変数がある場合の注意点です。
結論
@Binding変数を初期化する際はアンダースコア(_)を付ける
Cannot assign value of type 'Binding' to type 'String'
通常は@Binding
変数を定義しても、Memberwise Initializerが自動で初期化してくれるので自分でinitializeを定義する必要はありません。しかし、private
変数を使うなど自分でinit
を書く必要がある場合、以下のような書き方をするとエラーが発生します。
struct ContentView: View {
@State var text = "Hello"
var body: some View {
VStack {
SecondView(text: $text)
}
.padding()
}
}
struct SecondView: View {
@Binding var text: String
private var count = 0
init(text: Binding<String>) {
self.text = text // Cannot assign value of type 'Binding<String>' to type 'String'
}
var body: some View {
VStack {
Text(text)
}
}
}
エラーの内容は、「最初に定義したself.text
はString
型なのに引数のtext
はBinding<String>
型だからアクセスできません」といったものです。
https://qiita.com/crea/items/0b59722ab21e8c6cbb30
この記事ですごく分かりやすく解説されているのですが、
@Binding var text: String
は、実際は以下のような宣言として定義されています。
var _text: Binding<String>
var text: String {
get {
_text.wrappedValue
}
set {
_text.wrappedValue = newValue
}
}
それぞれのクラスは表のようになります。
名前 | 型 |
---|---|
_text | Binding<String> |
_text.wrappedValue | String |
text | String |
text
自体は値を持たず、String
型の_text.wrappedValu
をget
メソッドで返すだけであり、Binding<String>
型を表してるのは_text
だと分かります。
解決策
self.text
をself._text
もしくはただの_text
と直します。
struct ContentView: View {
@State var text = "Hello"
var body: some View {
VStack {
SecondView(text: $text)
}
.padding()
}
}
struct SecondView: View {
@Binding var text: String
private var count = 0
init(text: Binding<String>) {
self._text = text
}
var body: some View {
VStack {
Text(text)
}
}
}
終わりに
@Binding
とBinding<String>
の関係がごっちゃになってました...
参考:
https://ja.stackoverflow.com/questions/63300/swiftの初期化処理でエラーが発生する/63305#63305
https://inon29.hateblo.jp/entry/2020/05/02/134257