SwiftUIでは、@Bindingを使ってデータの双方向バインディングを簡単実現できますが、より柔軟にバインディングを作りたい場合には、Bindin構造体のget/setを活用する方法があります。
本記事では、Binding(get:set:)の基本的な使い方から、実用的なカスタムバインディングの例まで解説します。
そもそもBindingとは?
@Stateなどの変数を他のViewに渡して編集できるようにする仕組みです。
struct ParentView: View {
@State private var isOn: Bool = false
var body: some View {
ToggleView(isOn: $isOn) // ← $をつけてBindingを渡す
}
}
struct ToggleView: View {
@Binding var isOn: Bool
var body: some View {
Toggle("ON/OFF", isOn: $isOn)
}
}
Binding(get:set:)とは?
SwiftUIのBindingには以下のようなイニシャライザがあります。
Binding<T>(
get: @escaping () -> T,
set: @escaping (T) -> Void
)
これにより、「自前で読み書きのロジックを定義したバインディング」を作れます。
基本例:読み書きのロジックを分離したい場合
struct CustomBindingExample: View {
@State private var sliderValue: Double = 0.5
var body: some View {
let binding = Binding<Double>(
get: { self.sliderValue },
set: { newValue in
print("スライダーが変更されました: \(newValue)")
self.sliderValue = newValue
}
)
return VStack {
Text("Value: \(sliderValue)")
Slider(value: binding, in: 0...1)
}
.padding()
}
}
このようにsetでロジックを追加できるため、「副作用(ログ出力・バリデーションなど)」を持たせたいときに便利です。
応用例:Boolを反転させるBinding
struct ReverseToggleExample: View {
@State private var isVisible: Bool = true
var body: some View {
let reverseBinding = Binding<Bool>(
get: { !self.isVisible },
set: { self.isVisible = !$0 }
)
return Toggle("Hidden", isOn: reverseBinding)
.padding()
}
}
ここでは、isVisibleの逆の意味でトグルを操作できます。UIとロジックのズレを吸収できます。
実践的な使い方:String入力にバリデーションを追加
よくあるエラー:「Bindingを直接渡せない」
エラー例
エラーメッセージ:
Cannot convert value of type 'FocusState<String?>.Binding' to expected argument type 'Binding<String?>'
@FocusState private var focusedField: String?
TextField("名前", text: $focusedField) // エラー:Binding<String?>が必要
解決方法
Binding(get:set:)を使って明示的にラップします。
TextField("名前", text: Binding(
get: { focusedField ?? "" },
set: { focusedField = $0 }
))
まとめ
Binding(get:set:) | ロジックを挟んだ柔軟なバインディング |
setに副作用を加える | ログ・制限・非同期処理などを追加可能 |
getで逆転・変換など可能 | Bool反転、文字列変換、数値→文字列変換などに活用できる |
おすすめの活用シーン
- バリデーションや文字数制限
- ログ出力やアナリティクスの挿入
- UIの意味と内部ロジックのズレ解消(例:表示/非表示の反転)