UIを利用してRxSwiftのサンプルを確認する
UIを利用する場合は、RxSwift内で各UIをRxで拡張したクラスが用意されています。UIを利用した処理では、これらのクラスのプロパティやメソッドを利用することで、開発者自身がUI単位でObservableオブジェクトを生成する必要はありません。ここではRxSwiftの基本的な動きの例を、UIを利用して確認してみます。実際に画面上でUIを動かすとObserverパターンの使いどころや便利さがより実感できます。
Rxを利用してUIのイベントから処理を動かす/値を取得する
RxSwiftで用意されている各UIをRxで拡張したクラスでは、次のようにrxプロパティで各UIのイベントを監視できます。
#UIオブジェクト#.rx.#イベント#
どのようなイベントが利用できるかはUIによって異なるので、詳細はRxSwiftライブラリ内のクラスやドキュメントを参照してみてください。
import UIKit import RxSwift // -------(1) import RxCocoa class UISampleViewController: UIViewController { @IBOutlet weak var sampleButton: UIButton! // -------(2) @IBOutlet weak var sampleSwitch: UISwitch! let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() sampleButton.rx.tap.subscribe( // -------(3) onNext: { print( " tap ! " ) } ).disposed(by: disposeBag) sampleSwitch.rx.isOn.subscribe( // -------(4) onNext: { bool in print( bool ? " ON " : " OFF " ) } ).disposed(by: disposeBag) }
(1)最初にRxSwift/RxCocoaのライブラリをインポートします。
(2)次にUIButtonとUISwicthのオブジェクト/DisposeBagオブジェクトを用意します。
(3)UIButtonオブジェクトのrx.tapプロパティでタップイベントを取得できます。タップイベントをsubscribe(_:)メソッドで監視し、タップイベントが発生した際に「tap !」をコンソールに表示します。
(4)UISwitchオブジェクトのrx.isOnプロパティでスイッチのOn/Off状態を取得できます。On/Off状態をsubscribe(_:)メソッドで監視し、スイッチを切り替えた際にOnかOffかをコンソールに出力します。
RxSwiftを利用すると、従来のSwiftと違ってIBOutletで処理を用意する必要はありません。データストリームとしてイベントから流れて来る値を反映した処理を動かす、といった具合に、直感的に処理を記述できるのが特徴です。
delegateの代わりにRxで処理を行う
SwiftでUIの処理を行う際に必須となるのがdelegateです。delegate自体は、UIに固有の定番の処理を共通のフォーマットで記述できる点で非常に便利です。
しかし、 delegateをいくつも利用するとソースコードが長くなってしまったり、UIの定義と処理が離れてしまうため処理を追うのが困難になったりと、欠点もあります。RxSwiftでは、本来delegateで行う処理に関してもRxの拡張クラスで内包されており、Observerパターンで記述できます。
タブバーでアイコンを選択した際に、選択したアイコンのbadgeValueのみを10にする処理をRxSwiftで実装すると次の通りになります。本来ならばUITabBarDelegateで処理すべき内容が、RxSwiftを利用するとシンプルに記述できます。
self.tabBar.rx.didSelectItem.subscribe( onNext: { [weak self] tabItem in // 最初に全てのアイコンのbadgeValueを空にする self?.tabBar.items?.forEach{ $0.badgeValue = nil } // 選択したアイコンのbadgeValueを10に tabItem.badgeValue = "10" } ).disposed(by: disposeBag)
rx.didSelectItemプロパティは、UITabBarDelegateプロトコルのtabBar(_:didSelect:)メソッドで得られるUITabBarItemオブジェクトを参照できます。rx.didSelectItemプロパティをsubscribe(_:)メソッドで監視することで、タブが選択されたタイミングで任意の処理を行います。UITabBarDelegateプロトコルを利用するよりもシンプルでわかりやすく処理を記述することができます。サンプルのようにクロージャの中からselfでビューコントローラー自身を参照する場合には、weak/unownedで弱参照であることを明記してクロージャで得られる変数の前にselfを記述してください。
データバインドを利用する
データバインドとは、アプリケーションで利用するデータを画面上のビューなどと結合することを言います。Rxの世界では、画面上に存在するオブジェクトとRxで監視可能なオブジェクトの値を結合し、オブジェクトの値が変化した場合に即座に画面に反映するという処理でよく利用されます。Observableクラスが実装しているObservableTypeプロトコルのbind(_:)メソッドを利用します。
#Rxオブジェクト#.bind(to:#Rxオブジェクト#)
bind(_:)メソッドは結合するRxオブジェクトの型は等しい場合に限り利用可能です。入力欄に入力された文字列とラベルに表示する文字列をbind(_:)メソッドで結合する例は次の通りになります。UILabelには配置した場所がわかるように背景をグレーにしています。
class SampleBindViewController: UIViewController { @IBOutlet weak var textField: UITextField! @IBOutlet weak var label: UILabel! let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() self.textField.rx.text .bind(to:self.label.rx.text) // bund(_:)メソッドで2つの値を結合 .disposed(by: disposeBag) // 解放 }
サンプルを実行すると、入力欄に入力した文字列がそのままラベルに表示されます。
UITextFieldオブジェクトとUILabelオブジェクトのrx.textプロパティをbind(_:)メソッドで繋ぐだけで、リアルタイムに2つのオブジェクトの値を等価にすることが可能であることがわかります。このことをうまく利用すると、例えばUIで入力された値をビューコントローラー内でグローバルに持つ変数の値を結合し、リアルタイムに処理を行うといったことも可能となります。
まとめ
今回はRxSwiftの基本的な処理であるObserverパターンに関して、基礎的な紹介と簡単な使い方を説明しました。各種UIのrxプロパティで参照できるオブジェクトに関しては、非常に種類が多いので一度RxSwift配布元で確認してみてください。本来のSwiftよりも簡潔な記述で処理を実装できることがわかります。次回はObservable関連クラスに関してもう少し詳しく説明します。