【RxSwift】UITextFieldとUILabelのデータバインディング

#はじめに
- RxSwiftの導入を検討している。
- Swiftで書いてきたけれど、RxSwiftもこれから使っていきたい。

と言ったRxSwift初心者向けの記事です。
RxSwiftを使って簡単なデータバインディングのサンプルを作成します。


#この記事のゴール
この記事では、ViewControllerとViewModelの値をbindさせて、UITextFieldが更新されたら、UILabelが更新されるサンプルを作成します。

![sample.gif](https://qiita-image-store.s3.amazonaws.com/0/77845/f3d4b7ac-6052-bead-cb01-0b8a615c091e.gif)

#サンプルの全体像
<img width="497" alt="viewmodel.png" src="https://qiita-image-store.s3.amazonaws.com/0/77845/bf57908c-ff4d-fe4c-9782-c264085462f9.png">

ViewControllerとViewModel間でデータバインディングを行なって、値が更新されたらViewが更新します。

#下準備
Xcodeで新規プロジェクトを作成して、RxSwiftとRxCocoaをインポートします。

##RxSwiftとRxCocoaをインポートする

[【Swift】CarthageでRxSwiftをインポート](https://qiita.com/hananaonao/items/1ac70d5b48e5c21955d6)

こちらの記事を参考にRxSwiftをプロジェクトにインポートしてください。

#Viewの準備

まずStoryBoardにUITextFieldとUILabelを置いて、ViewControllerに紐付けます。

```ViewContoller.swift
import UIKit

class ViewController: UIViewController {
    @IBOutlet weak private var textField: UITextField!
    @IBOutlet weak private var titleLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}
```


#TextFieldの更新を監視
続いてTextFieldが入力を監視するコードをViewControllerに追加します。

```ViewContoller.swift
import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {
    @IBOutlet weak private var textField: UITextField!
    @IBOutlet weak private var titleLabel: UILabel!
    
    private let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        bind()
    }
    
    private func bind() {
        textField.rx.text.orEmpty.asObservable()
            .subscribe { [weak self] in
                //　ここでViewModelに値の更新を通知します。
            }
            .disposed(by: disposeBag)
    }
}
```

#ViewModelで対象の値の作成

```ViewModel.swift
import RxSwift

class ViewModel {
    var title: Observable<String> {
        return titleSubject
    }
    private let titleSubject = PublishSubject<String>()
}
```
監視対象の変数を作成して、管理をします。
対象となるtitleSubjectは、外から更新できないようにカプセル化します。

#ViewControllerで値を受け取るコードを追加

```ViewContoller.swift
import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {
    @IBOutlet weak private var textField: UITextField!
    @IBOutlet weak private var titleLabel: UILabel!
    
    private let viewModel = ViewModel()
    private let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        bind()
    }
    
    private func bind() {
        textField.rx.text.orEmpty.asObservable()
            .subscribe { [weak self] in
                //　ここでViewModelに値の更新を通知します。
            }
            .disposed(by: disposeBag)
        
        viewModel.title.asObservable()
            .subscribe { [weak self] in
                //　ここでViewModelの更新を受け取ります。
            }.disposed(by: disposeBag)
    }
}

```

#ViewControllerからVideModelの値を更新する

ViewModelの管理対象はカプセル化していますので、新しく関数を作って値の更新を行います。

```ViewContoller.swift
    private func bind() {
        textField.rx.text.orEmpty.asObservable()
            .subscribe { [weak self] in
                guard let value = $0.element else { return }
                self?.viewModel.set(text: value)
            }
            .disposed(by: disposeBag)
        
        viewModel.title.asObservable()
            .subscribe { [weak self] in
                //　ここでViewModelの更新を受け取ります。
            }.disposed(by: disposeBag)
    }
```

```ViewModel.swift
import RxSwift

class ViewModel {
    var title: Observable<String> {
        return titleSubject
    }
    private let titleSubject = PublishSubject<String>()
    
    func set(text: String) {
        titleSubject.onNext(text)
    }
}

```

これでViewControllerからVideModelの監視された値を更新することができました。

#ViewModelの更新を受け取ってViewを更新する
ViewModelの更新をすることができました。
最後に先ほど作成したViewModelの値の更新を受け取るコードの中に、Viewを更新するコードを追加します。

```ViewContoller.swift
    private func bind() {
        textField.rx.text.orEmpty.asObservable()
            .subscribe { [weak self] in
                guard let value = $0.element else { return }
                self?.viewModel.set(text: value)
            }
            .disposed(by: disposeBag)
        
        viewModel.title.asObservable()
            .subscribe { [weak self] in
                self?.titleLabel.text = $0.element
            }.disposed(by: disposeBag)
    }
```
簡単にUITextFieldとUILabelのデータをバインディングすることができました。

#サンプルコード

[https://github.com/hananao/RxSwift_Begin_Sample_UITextField_UILabel](https://github.com/hananao/RxSwift_Begin_Sample_UITextField_UILabel)


#まとめ
細かい部分の説明は不十分ですが、簡単にRxSwiftを使ってデータバインディングすることができました。

記事について間違っている部分やご指摘などありましたら、コメントにお願いします。