データバインディング
前回までで、入力系UIの配置とコードの追加について説明しました。ここでは具体的に入力系UIとコードの関係について学びましょう。
UIの入力値とコードの関係
入力欄のUIであるTextFieldのinitメソッドの書式は次のとおりであることは前回説明しています。
init(LocalizedStringKey, text: Binding<String>)
text: Binding<String>は、プログラム内の変数と入力欄の値を結びつける引数です。
つまり、TextFieldを利用する際には、あらかじめ入力欄の値に相当する変数をコードの中で用意しておく必要があります。
具体的に入力欄の値とコードの連携を確認するために、サンプルのコードを次のように編集します。
import SwiftUI struct ContentView: View { var subject: String = "Hello, Swift" var message: String = "ボタンを押しました" @State var inputText: String = "テキスト入力です" var body: some View { VStack { TextField("入力してください", text: $inputText) .font(.title) .textFieldStyle(.roundedBorder) .padding() Button("Button") { print(message) } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
最初に、入力欄の値と結びつける変数を、「inputText」の名前で宣言します。UIの入力値と結びつける変数であることを明記するために「@State」を変数の前につけます。
つぎにここで宣言した変数をTextFieldの入力値を結びつける引数とします。このときには、UI側からコード内の変数と結びついていることを明記するために、変数名の前に「$」をつけます。
コードを記述した段階でコード内の変数とTextFieldの入力値が結びついているので、プレビュー画面でも入力欄に変数inputTextの値である「テキスト入力です」が自動的に入力欄に入力されています。
このように、UIの入力値とコードの変数を結びつけることをデータバインディングまたは単にバインディグ、結びつける変数のことをバインディング変数と呼びます。
バインディングの仕組みを整理すると次のようになります。
・入力系UIを配置する前に、バインディング変数を宣言しておく。
・入力系UIのインスタンスの引数にバインディング変数を指定する。
アプリ開発を進めるにあたって、さまざまな入力系のUIを利用します。バインディングの基本的なルールは上記の2点なので、ここで覚えておいてください。
また、「inputText」のように変数内の単語の区切りの最初を大文字にすることをキャメライズといいます。変数の意味をわかりやすくするために、キャメライズはよく利用されます。
入力値の変更を確認する
アプリを動かして入力値がコードで取得できることを確認してみましょう。
コードを編集してボタンを押した時にバインディング変数の値をコンソールに出力できるようにします。
import SwiftUI
struct ContentView: View {
var subject: String = "Hello, Swift"
var message: String = "ボタンを押しました"
@State var inputText: String = "テキスト入力です"
var body: some View {
VStack {
TextField("入力してください", text: $inputText)
.font(.title)
.textFieldStyle(.roundedBorder)
.padding()
Button("Button") {
print(self.inputText)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
変数の前に「self.」とつけているのは、ContentView構造体自身で宣言した変数、という意味です。
構造体やクラスの中で宣言した変数を、同じオブジェクトで利用する際には、コードをわかりやすく「self」をドットで区切ってつけるほうがいいです。
コードを編集した後は、シミュレーターを起動して入力欄の値を変更してボタンを押してください。
サンプルでは入力欄の値を「テキスト入力しました」に変更してボタンを押しています。
ボタンを押すと、コンソールに「テキスト入力しました」と表示され、入力欄の値がコード内の変数「inputText」に入っていることが確認できます。
コンソールにはprintメソッドでの出力以外にも、Xcode内のログが自動的に出力されることがあります。コンソール内のログは、赤丸のゴミ箱ボタンを押すことでクリアできます。
改めて引数の書式を確認する
バインディングの仕組みがわかったところで、改めてTextFieldのinitメソッドの書式を確認してみます。
init(LocalizedStringKey, text: Binding<String>)
バインディング用の引数は「text: Binding<String>」ですが、通常の変数の型とは異なる書式となっています。
この型の書式の意味を考えてみます。
バインディング変数を表す「Binding<String>」は、コード内の「@State」によって宣言されるバインディング変数にあたります。
バインディング変数の宣言を確認すると次の通りです。
@State var inputText: String = "テキスト入力です"
「@State」は変数の前に付けられるバインディングを意味する変数の修飾子です。変数の型は「String」で宣言されています。
つまり、バインディングというのは変数の状態を指すだけで、変数の型とは無関係と考えることができます。
「Binding<String>」は、バインディングの状態にあるString型のことだと判断できます。
Swiftでは、オブジェクトの2つの性質を表すときには、「概要<詳細>」という書き方をすることも覚えておいてください。