LoginSignup
13
11

More than 5 years have passed since last update.

RxSwiftのExamplesにしれっと入ってる双方向データバインディングの演算子がイケてた

Last updated at Posted at 2017-05-29

こんばんは!:octocat:

RxSwift (RxCocoa)を使ってモデル←→ビューのお互いの更新を伝え合う双方向データバインディングをやってみます。

SwiftBond では双方向データバインディングがサポートされているのですが RxSwiftのドキュメントにはそのような記述はなく、綺麗に書く方法ないかな〜とExamplesを眺めていたらそれっぽいものを見つけたのでご紹介します。

やってること

hoge.gif

  • 登場人物
    • ラベル
      • 最新の値を表示し続ける
    • テキストフィールド ←こいつに双方向bindを実装します
      • 最新の値を表示し続ける
      • 値を入力できる
    • ボタン
      • 値を初期値に変更できる

このUIにおいて、

  • テキストフィールドで入力した内容が即時ラベルに反映される。
  • ボタンの押下で書き換わった内容が即時テキストフィールドに反映される。

という点において双方向のデータバインディングを実現してみます。

Before

import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {
    private var item = Variable<String?>("Hello!")
    private let disposeBag = DisposeBag()

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var textField: UITextField!

    @IBAction func resetButtonHandler(_ sender: UIButton) {
        item.value = "Hello!"
    }

    @IBAction func textFieldHandler(_ sender: UITextField) {
        item.value = sender.text
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        setup()
    }

    private func setup() {
        // モデルからビューへ
        item.asObservable().bind(to: textField.rx.text).disposed(by: disposeBag)
        // ビューからモデルへ
        textField.rx.text.subscribe(onNext: { [weak self] text in
            self?.item.value = text
        }).disposed(by: disposeBag)

        // 最新の値をラベルで表示しておく
        item.asObservable().bind(to: label.rx.text).disposed(by: disposeBag)
    }
}

ここで Bidirectional Operator <-> の登場です。

左辺にビュー、右辺にモデルが来るように書きます。
さらにそのままだと返り値が未使用と言われるので _ = を先頭につけておきます。
(一応例にもそう書いてあったのですが、万が一メモリリークの危険性踏んでたら教えて頂きたく...! :bow:

After

import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {
    private var item = Variable<String?>("Hello!")
    private let disposeBag = DisposeBag()

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var textField: UITextField!

    @IBAction func resetButtonHandler(_ sender: UIButton) {
        item.value = "Hello!"
    }

    @IBAction func textFieldHandler(_ sender: UITextField) {
        item.value = sender.text
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        setup()
    }

    private func setup() {
        _ = textField.rx.text <-> item // ここ(´∀` )
        item.asObservable().bind(to: label.rx.text).disposed(by: disposeBag)
    }
}

ユーザID+パスワードや、住所氏名年齢電話番号・・・のような設定するコンポーネントが多い画面で活躍してくれそうです!
だんだんRxSwiftが面白くなってきた今日このごろです:relieved: おやすみなさい。

13
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
11