Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

こんばんは!: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: おやすみなさい。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした