「 @Stateで作った変数の更新を別の画面でも共有したい… 」
そんな時に使われるのが、SwiftUIのデータバインディング機能の一つである@Bindingです。
@Stateと@Bindingは密接な関係にあります。それぞれがどのように作用するのか、どう使えばいいのかを見ていきましょう。
@Stateの使い方についてはこちらの記事で解説しております。
[ 本記事はこんな人におすすめ ]
・SwiftUIを学習している
・データバインディングについて知りたい
・@Bindingの使い方を知りたい
環境・バージョン
> Swift 5.7.2
> Xcode 14.2
> macOS 12.5 Monterey
@BindingはSwiftUIにおけるデータバインディング機能の一つです。
変数に@Bindingを付与することで、親子関係にあるView内の@Stateプロパティ(状態変数)のデータを共有します。
このように@Stateから@Bindingへデータを紐づけることを、プロパティへの参照を渡すとも表現されます。
@Bindingを使う上でのポイントは以下です。
@Bindingの動きを見るため、「AView」「BView」二つのViewを用意しました。
15行目、AViewの中からBViewを呼び出しており、2つのViewは親子関係です。
// 親View ⇨ 呼び出す側のView
struct AView: View {
@State var isCheck: Bool = false // ⬅︎Bool値が保持される状態変数
var body: some View {
VStack(spacing: 20) {
// ベルマーク "true"と"false"でデザインが変化
Image(systemName: isCheck ? "bell.fill" : "bell.slash")
.font(.largeTitle)
.foregroundColor(.black)
BView(isCheck: $isCheck) // ⬅︎ 子Viewを呼び出している(この時に参照を渡す)
} // VStack
} // body
} // View
// 子View ⇨ 呼び出される側のView
struct BView: View {
@Binding var isCheck: Bool // 親Viewのプロパティ参照を受け取る
var body: some View {
Button("切り替えボタン") {
isCheck.toggle() // 参照共有しているBool型ブロパティの値を反転する
}
} // body
} // View
今回はこの2つのViewを使って@Bindingの動きを見ていきましょう。
@Stateと@Bindingでデータ共有されるView間は親子関係である必要があります。
呼び出す側のViewを「親View 」、呼び出される側のViewを「子View」と呼びます。
今回のコードだと、
・親View ⇨ 呼び出す側の「AView」
・子View ⇨ 呼び出される側の「BView」
となりますね。
親View側で宣言している@Stateプロパティへの参照を子Viewの@Binding変数に渡します。
これによってデータの状態共有が実現できます。
「参照を渡す」とは?
@Bindingについて、公式ドキュメントでは以下のように書かれています。
公式ドキュメント:
バインディングは、データを直接格納する代わりに、他の場所に格納されている真実のソースにプロパティを接続します。Bindingプロパティラッパーを使用して、その親ビューのプロパティへのバインディングを作成することができます。
上記引用にある「真実のソース(source of truth)」とは、親View側にある@State変数のことを指します。@Stateでマークしたプロパティは信頼できる情報源となり、状態を共有するデータにおける情報(ソース)元になります。
親View側のプロパティ(@State)を信頼できるソース元とし、その状態を子View側のプロパティ(@Binding)が参照できるようにソースを渡すという考え方が「参照を渡す」のイメージです。
@Stateプロパティと@Bindingプロパティを紐付けるための手順をみていきましょう。
[プロパティ紐付けの手順]
子Viewの中で、親Viewのデータを参照するための@Bindingプロパティを宣言します。
変数の型は双方向で一致させます(今回の場合だとBool型)。
親View側のプロパティを参照とするので、@Binding変数に初期値は代入しません。
変数の名前は親View側と異なる命名をすることができますが、基本的には両方向で同じ命名にしておいた方が読みやすいかと思います。
子View側で@Binding変数の準備ができたら、親View側から子Viewを呼び出します。
この時、引数の頭に「$」(ドルマーク)を付けることで子Viewの@Bindingプロパティと紐付けます。
プロパティへの紐付けが完了した@Binding変数は、参照元である@State変数と同様にSwiftUIの監視(モニタリング)対象になります。
これによって子Viewと親Viewのどちらからもプロパティの更新が可能になり、更新を検知しSwiftUIが双方のViewを再描画します。
では、シミュレータ「Command + R」で連動的なViewの更新を確認してみましょう。
双方のViewのコードをおさらいしておきます。
[AView]
親View側は、プロパティの更新でベルマークのデザインが変化します。
// 親View ⇨ 呼び出す側のView
struct AView: View {
@State var isCheck: Bool = false // ⬅︎Bool値が保持される状態変数
// ⬇︎ trueなら"有効", falseなら"無効"
Image(systemName: isCheck ? "bell.fill" : "bell.slash")
.font(.largeTitle)
.foregroundColor(.black)
BView(isCheck: $isCheck)
} // VStack
} // body
} // View
[BView]
子View側では少しボタンのテキストに変更を加えました。
親Viewと紐付けた参照プロパティがtrueならON、falseならOFFに表示分岐します。
// 子View ⇨ 呼び出される側のView
struct BView: View {
@Binding var isCheck: Bool
var body: some View {
Button(isCheck ? "ON" : "OFF") { // ⬅︎ trueなら"ON", falseなら"OFF"
isCheck.toggle()
}
} // body
} // View
[画面処理の流れ]
AView側のベルマーク、BView側のボタンテキスト、双方がプロパティ更新に連動して変化していますね。
このように親子関係にあるViewから@Stateプロパティ(状態変数)への参照を受け取って、双方でデータの更新を共有するのが@Bindingの機能です。
もちろん上記例の逆方向からの更新も可能で、AView側でプロパティを変化させれば、BViewも連動してViewが更新されるということです。
@Binding変数が宣言されているView単体をプレビュー画面に表示するには、Binding化された不変の値をプロパティの初期値として代入する必要があります。
以下のように、Binding化していない値を代入しようとするとエラーがでます。
Cannot convert value of type ‘Bool’ to expected argument type ‘Binding<Bool>’
型 ‘Bool’ の値を期待される引数型 ‘Binding<Bool>’ に変換できません。
Binding化された不変値の代入方法は以下です。
「true」「false」「10」「”おはよう”」などの不変の値を「.constant」メソッドで包んであげることで、Binding化された不変値として代入します。
公式ドキュメント:
不変値(ふへんち)とは
不変値(Immutable balue)とは、一度値が定義されると、その後変更できない値のことを指します。
例えば、文字列や数値は不変値の一例です。文字列が 「let text = “Hello, world!”」 と設定された場合、この文字列自体を変更することはできません。文字列を変更する必要がある場合は、新しい文字列を作成する必要があります。
ここでの不変値は、「10」「true」「”おはよう”」などの値そのものを指します。値そのものは変化しないので、その値をそのままBinding変数として使うためにconstantしています。
例では@Binding変数がBool型ですが、
・String型なら Binding<String> ⇨ .constant(“おはよう”)
・Int型なら Binding<Int> ⇨ .constant(10)
といった具合に、対象の@Binding変数によって値の型を合わせましょう。
これで以下のように、Binding変数を保持するViewのプレビュー表示ができます。
この場合@Binding変数に代入している値は不変値なので、プレビュー内でボタンタップしても変数の値は変化せず、Viewの更新もされません。
今回はSwiftUIのデータバインディング機能の一つ、@Bindingについてでした。
@Bindingの要点をおさらいしておきましょう。
・データを共有するView間は親子関係である
・プロパティへの参照を渡す
・プロパティを双方向から監視(モニタリング)する
複数のView間でデータの更新を共有したい場面は多くあります。
@Stateと@Bindingを組み合わせることで、画面実装の幅がグッと広がるでしょう。
ぜひ使ってみてください👍
[ @Stateについて ]
\ SHARE /
アプリ開発が学べる勉強会を開催中!
CodeCandyではアプリ開発を学ぶための勉強会を定期開催しています。
学習する習慣を身につけたい、他の参加者と作業したい、アプリ開発の基本をマスターしたい、という方のために無料で学べる勉強会です。
グループにメンバー登録して頂くと、イベント開催時にメールで通知されます。
徹底した基礎学習からマスターするiPhoneアプリ開発集中オンライン講座開講!
本書「iPhoneアプリ開発集中講座」を執筆している現役エンジニア講師陣が直接に指導!
基礎、課題実習で実践力を鍛えて、オリジナルアプリ公開までチャレンジ!
充実した転職支援もあるので、エンジニアへ転職したい人にもおすすめです!
まずは、現役エンジニアに相談できる無料相談をご利用ください。
2022年2月よりSwift学習を始め、4月からiOSアプリ開発オンラインスクール「CodeCandy」にてアプリ開発を学ぶ。 2023年10月に個人開発アプリ「unico」をリリース。現在はアプリの機能アップデートをしながら、スクール運営の技術ブログの執筆や、出版書籍の入稿チェック・デバッグにも携わる。