RxSwiftのbindToについて
RxSwiftにはbindToが大きく分けて2種類あります。
引数にobserverを取るものと、binderを取るものです。 引数にvariableを取るものは基本observableを取るものと動きが同じです。
以下のような特徴があります。
引数にobserver/variableを取るもの
内部的に即subscribeが呼ばれる。
実装はこうなっています。(複数ありますが、簡単なほうを抜粋)
/** Creates new subscription and sends elements to observer. In this form it's equivalent to `subscribe` method, but it communicates intent better, and enables writing more consistent binding code. - parameter observer: Observer that receives events. - returns: Disposable object that can be used to unsubscribe the observer. */ @warn_unused_result(message="http://git.io/rxs.ud") public func bindTo<O: ObserverType where O.E == E>(observer: O) -> Disposable { return self.subscribe(observer) }
A=>B というシーケンスを作って即実行したい時に使えます。
引数にbinderを取るもの
内部的には引数のbinder: Self -> R のクロージャがselfを引数に実行されるだけ。
実装はこうなっています。(複数ありますが、簡単なほうを抜粋)
/** Subscribes to observable sequence using custom binder function. - parameter binder: Function used to bind elements from `self`. - returns: Object representing subscription. */ @warn_unused_result(message="http://git.io/rxs.ud") public func bindTo<R>(binder: Self -> R) -> R { return binder(self) }
A=>Bというシーケンスだけ作っておいて、後で別のシーケンスとつなげたり、subscribeのタイミングをコントロールしたりする時に役立ちます。
ちょっと例が雑ですが、以下のようにログイン状態の時とそうでない時でシーケンスを変えるなんて使い方はいかがでしょうか。
var loggedIn = true override func viewDidLoad() { super.viewDidLoad() let number1Seq01 = number1.rx_text.bindTo(verifyString).retry(3) if loggedIn { number1Seq01 .bindTo(doThisOnlyWhenLoggedIn) .bindTo(number4.rx_text) .addDisposableTo(disposeBag) } else { number1Seq01 .bindTo(number4.rx_text) .addDisposableTo(disposeBag) } } func verifyString(observable: ControlProperty<String>) -> Observable<String> { return Observable.create { observer in /* Do something useful... */ return observable.subscribeNext { value in print(#function) observer.onNext(value) } } } func doThisOnlyWhenLoggedIn(observable: Observable<String>) -> Observable<String> { return Observable.create { observer in /* Do something useful... */ return observable.subscribeNext { value in print(#function) observer.onNext(value) } } }
まとめ
先日参加した 第2回RxSwift勉強会 @ Sansanにて「bindToはsubscribeと同じ」という言及があって、アレそうだったっけ?と思って再度検証してみました。
厳密にはsubscribeと同じ意味のものと、そうでないものがありました。bindToのbinderファンクションの仕組みを利用する事で、複雑なシーケンスも普通の変数として取り回す事も出来るようになりました。
実際には、私は起動シーケンスの処理でこの Observable.create
とbindTo を多用しています。色々な処理を様々な依存関係で記述する必要があるような時に、あると便利な道具だと思います。
ご意見募集中です。