はじめに
SwiftUIで@
がついたものをPropertyWrapper
というらしいですが、その1つに@State
があります。
今回は@State
について深ぼる記事になります。
- はじめに
- 環境
- 概要
- 基本的な使い方
- @Stateつけないと変数の値を変えられない件
- なぜ@Stateをつけるとなぜ変えられるのか?
- @Stateの変数を変更したら画面更新される
- @Stateの変数を引数の値で初期化する場合に起きる問題
- おわりに
環境
この記事の情報は次のバージョンで動作確認しています。
概要
- View内の変数の値を変えるため
- 変数の値が変わったことをViewに通知するため
基本的な使い方
@Stateを頭につけて、あとは普通に変数宣言するだけ
@State private var hoge: Bool
@Stateつけないと変数の値を変えられない件
変数の更新をVIewに伝えられない問題もあるんですが、一番の問題はそこじゃないんです。
そもそも変数の値を変えるタイミングはButtonなどが持つクロージャ内になります。
Viewはstructであるため、クロージャの中だとself(自分自身)の変更をしようとすると下記エラーが起きます。
Cannot use mutating member on immutable value: 'self' is immutable
つまり 変数の中身を変えられない ということになります。
これが@Stateをつける一番の意味となります。
余談ですが、
Swiftの言語仕様として、上記エラーはクロージャじゃなくメソッドならmutating
をつければエラーを回避可、
そもそもclassであればクロージャ内で書き換えできるみたいです。
どちらにせよViewに変更を通知できない問題は残るので意味ないですが。。
なぜ@Stateをつけるとなぜ変えられるのか?
A:分かりません
これがまだ分かって分かっていません。とりあえずおまじないと思っておきます。
@Stateの変数を変更したら画面更新される
これが@Stateを使う上で一番肝心な部分になります。
@Stateの変数の値が変わると画面が更新されます。。。
うん。それは察してるとは思うけど内部的にどうなってるかですよね。
分かる範囲で検証してみました。
initが呼ばれてたのでView自体が再生成されているってことです。
子View側の@Stateの変数の値が変わった場合にどうなるのか?
@Stateの変数を引数の値で初期化する場合に起きる問題
Variable used before being initialized
条件は不明ですがこのエラーが出てしまうことがあります。
この場合初期化方法を変えるとうまくいきます。
struct SecondView: View { @State private var text: String init(str: String) { _text = State(initialValue: str) } var body: some View { VStack { TextField("Hoge", text: $text) } } }
ポイントとしてはtext
を_text
とアンダースコア(_)をつけて変数にアクセスします。
代入する際は State(initialValue: 値)
の形をとります。
エラーが出るケースと出ないケースがあるので、エラーが出た場合はこれを試してみてください。
おわりに
最後まで見ていただきヘペトナス!
読者登録・Twitterのフォローもお願いします。