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


はじめに

  • RxSwiftの導入を検討している。
  • Swiftで書いてきたけれど、RxSwiftもこれから使っていきたい。

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

この記事のゴール

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

サンプルの全体像

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

下準備

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

RxSwiftとRxCocoaをインポートする

【Swift】CarthageでRxSwiftをインポート

こちらの記事を参考に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

まとめ

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

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