RxSwiftでUIPickerViewとUITextFieldのテキストをバインドする

最近RxSwiftの勉強をしていて思いついたバインドをやってみる。
UIPickerViewからデータを選択し、そのデータをUITextFieldのテキストにセットするものである。 f:id:culumn:20180606232037p:plain

UIPickerViewUITextFieldの入力として使用する

まずUIPickerViewUITextFieldの入力のViewとして使用するには、UITextFieldのプロパティinputViewUIPickerViewインスタンスを代入するだけでよい。

textField.inputView = UIPickerView()

ただ、これだけではUIPickerViewdataSourceが実装されていないので、選択するデータがない。また、UIPickerViewから選択したときのイベントをdelegateでハンドリングし、そのデータをUITextFieldのテキストにセットする必要がある。
今回はUIPickerViewdataSourcedelegateを用いての実装は省略するが、まあ面倒である。そこで本題のRxSwiftを用いた実装を次に紹介する。

RxSwiftでUIPickerViewUITextFieldをバインドする

class ViewController: UIViewController {
    @IBOutlet weak var strTextField: UITextField!
    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        let strPickerView = UIPickerView()
        strTextField.inputView = strPickerView

        // strsをstrPickerViewのデータ(タイトル)としてバインド
        let strs = ["abc", "def", "ghi"]
        Observable.just(strs)
            .bind(to: strPickerView.rx.itemTitles) { _, str in
                return str
            }
            .disposed(by: disposeBag)
        // strPickerViewから選択したデータ(タイトル)をstrTextFieldのテキストにバインド
        strPickerView.rx.modelSelected(String.self)
            .map { strs in
                return strs.first
            }
            .bind(to: strTextField.rx.text)
            .disposed(by: disposeBag)
    }
}

比較するべきdataSourcedelegateを用いた実装が今回はないが、上記のコードを見るだけでも簡潔に書けていることがわかると思う。

まとめ

bind()メソッドでデータをバインドできるのは便利だと感じた。また、modelSelected()メソッドがジェネリクスを用いて、データとしてバインドした任意の型を取得できるのも良いと感じた。UIPickerViewDelegatepickerView(_:didSelectRow:inComponent:)は選択したデータの行などしか取得できないので、それに比べると便利だと思う。

今記事のコードを用いたサンプルをgithubにあげておく。

github.com