SwiftBondでデータバインドを実現する
Modelを実行した後、画面更新処理をせこせこ実装するのが面倒...。
”更新処理を意識せずにiOSアプリが書けんものか”と思って色々調べてみると
SwiftBondというOSSライブラリを発見しました。
github.com
コイツを上手く使ってやると
ViewControllerとViewModel間でデータバインドが簡単に実現できます。
(ViewModelは必須ではないですが、Modelの実行結果の変換処理が
ViewControllerから切り離せるのでViewModelがあった方が良いですね)
1. SwiftBondを導入する
CocoaPodsを使って簡単インストールです。
use_frameworks! pod 'Bond', '~> 4.0'
2. ViewModelを作成する
ViewModelクラスを作成します。
今回はUITextFieldにバインドするString型変数1つを持ったクラスを作ります。
import Foundation import Bond class ViewModel { /** UITextFieldに対応する変数 */ var text = Observable<String?>("初期値") }
ポイントはString型で初期化するのではなく
SwiftBondが提供するObservableというWrapperクラスを使う所です。
(Observableクラスがデータバインドの機能を下支えしています......!)
3. ViewControllerを作成する
ViewControllerクラスを作成します。
StoryboardとバインドされたUITextField型変数と先ほど作成した
ViewModel型変数の2つをメンバ変数として持たせておきます。
import UIKit import Bond class ViewController: UIViewController { /** バインド対象のUITextField */ @IBOutlet weak var inputBox: UITextField! /** ViewModel */ let viewModel = ViewModel() override func viewDidLoad() { super.viewDidLoad() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
4. ViewControllerとViewModelのBind処理を書き足す
では、UITextFieldとViewModelをバインドしていきます。
今回はViewController側にバインド定義処理を実装したprivateな関数
「bindViewAndModel」を作りviewDidload関数から呼び出してみます。
(バインド定義が増えるとviewDidloadがゴミゴミするのでその対策)
override func viewDidLoad() { super.viewDidLoad() bindViewAndModel() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } /** ViewとModelをバインドする */ private func bindViewAndModel() { inputBox.bnd_text.bindTo(viewModel.text) }
SwiftBondの提供する「bindTo」関数を使います。
これでUITextFieldの変更が自動でViewModelの変数textに伝搬します。
print関数でtextの中身を出力するような処理を書いて試してみてください。
ちなみに、「bindTo」関数は単方向のデータバインドを実現します。
双方向のデータバインドを実現したい場合は
「bidirectionalBindTo」関数を使えばOKです。
/** ViewとModelをバインドする */ private func bindViewAndModel() { inputBox.bnd_text.bidirectionalBindTo(viewModel.text) }
補足. ViewModelの変数へのアクセス
実際にバインドが成功しているか確認する場合の注意点です。
前述の通り、ViewModelの変数はObservable型として定義しているので
単純に print(viewModel.text) なんてしてもデータは正しく表示されません。
SwiftBondのvalue変数経由でUnwappingした値を取り出す必要があります。
func pushCheckBtn() { print(viewModel.text.value!) }
value変数はOptional型なのでさらにUnwrappすることも忘れずに!