@Stateと@Bindingの関係性
SwiftUIでは 「状態を1箇所で管理し、Viewはそれを元に描画する」 という考え方が基本になります。
@State と @Binding は、その設計を支えるためのセットの仕組みです。
この記事では
-
@Stateが「状態を所有する」もの -
@Bindingが「その状態を参照・操作する」もの
という関係性を、シンプルな例を使って解説します。
@State とは
@State は Viewが内部で管理する状態 を表すためのプロパティラッパーです。
@State を付けた値は、単なる変数ではなく「UIの状態(State)」として SwiftUI に管理されます。
@State の主な特徴
1. 値が変わると View が再描画される
@State の値が変更されると、SwiftUI はその View 再描画をします。
struct StateSampleView: View {
@State private var count = 0
var body: some View {
Button("Count: \(count)") {
count += 1
}
}
}
この例では、count が更新されるたびに body が再計算され、
表示されているテキストも自動的に更新されます。
2. View が再生成されても値が保持される
SwiftUI の View は 状態が変わるたびに再生成される 可能性があります。
しかし @State の値は View の構造体そのものではなく、
SwiftUI が別で管理しているため、View が再生成されても値は保持されます。
この仕組みにより、「Viewは軽量」「状態はSwiftUIが管理」 という設計が成り立っています。
3. ローカルな状態管理に使う
@State は その View 専用の状態 です。
他の View から直接アクセスすることはできません。
別の View からこの状態を操作したい場合に登場するのが @Binding です。
なぜ @Binding が必要なのか?
もし子 View が独自に @State を持ってしまうと、
- 親 View の状態
- 子 View の状態
が分離し、どちらが正しいのか分からなくなります。
SwiftUIでは状態は1箇所で管理し、複数の View から参照するという設計が推奨されています。
@Binding はそのための仕組みです。
親Viewと子Viewで @State と @Binding を使ってみる
// 親のView
struct ParentView: View {
@State private var isOn = false
var body: some View {
ChildView(isOn: $isOn)
}
}
// 子のView
struct ChildView: View {
@Binding var isOn: Bool
var body: some View {
Toggle("Switch", isOn: $isOn)
}
}
「$」は何をしているのか
-
isOn→ 値そのもの(Bool) -
$isOn→ その値への「読み書きできる接続」(Binding<Bool>)
isOn は単なる Bool の値です。
そのため、この値を渡しただけでは「今の状態」を読むことはできますが、
変更結果を親Viewに反映することはできません。
一方で Toggle のような入力UIは、
- 現在の値を表示する
- ユーザー操作によって値を変更する
という 読み取りと書き込みの両方 が必要になります。
そのため SwiftUI では、値そのものではなく
「値を読み書きできる接続」である Binding を渡す設計になっています。
@State が付いたプロパティに $ を付けると、
その状態に対する Binding を取り出すことができます。
つまり、
-
isOnはBool -
$isOnはBinding<Bool>
です。
Toggle はこの Binding を通して現在のON/OFFを読み取り、
タップ操作によって値を書き換えます。
その結果、親Viewが持っている @State の値も更新されます。
@State と @Binding の役割まとめ
| 役割 | 説明 |
|---|---|
@State |
状態を所有する |
@Binding |
状態を借りて操作する |
-
$はStateをBindingに変換するために使われます
よくあるミス
- 子Viewで
@Stateを持ってしまう -
@Bindingを初期化しようとする - $ を付け忘れる
おわりに
@State と @Binding はセットで使われる仕組みで、
「状態を持つ側」と「その状態を操作する側」を分けるためのものです。
状態は1箇所で管理し、必要なViewにだけ Binding として渡す。
この考え方を意識すると、SwiftUIの設計がぐっと理解しやすくなります。
参考
Apple Developer Documentation