読者です 読者をやめる 読者になる 読者になる

スマートデバイスアプリ開発のあれやこれや

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することも忘れずに!