【RxSwift】Hot変換オペレータの1つであるshareReplayを使ってみる
記事内に広告を含む場合があります。記事内で紹介する商品を購入することで、当サイトに売り上げの一部が還元されることがあります。
最近、RxSwiftについて勉強中です。
今回は、Hot変換オペレータの1つであるshareReplayを使ってみたので記事にまとめてみました。
RxSwiftはまだ勉強中なので、どこか間違っている箇所があればご指摘いただけると嬉しいです。 ⇒ https://twitter.com/akio0911
UITextFieldの入力をそのまま2つのUILabelに表示する
例として、1つのUITextFieldに入力された文字列を、2つのラベルにそのまま表示するアプリを考えてみましょう。
RxSwiftを使ったコードとしては、以下のようになります。
@IBOutlet weak var textField: UITextField! @IBOutlet weak var label1: UILabel! @IBOutlet weak var label2: UILabel! let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() textField.rx_text.bindTo(label1.rx_text).addDisposableTo(disposeBag) textField.rx_text.bindTo(label2.rx_text).addDisposableTo(disposeBag) }
これでユーザーがテキストフィールドに文字列を入力すると、ラベルへリアルタイムに反映されるようになります。
ここまでは特に問題ないかなと思います。
UITextFieldの入力を加工して、2つのUILabelに表示する
次はそのまま表示せずに簡単な加工を行ってみましょう。
テキストフィールドに入力された文字列の先頭と末尾に*を付加し、それを2つのラベルへリアルタイムに反映させます。
コードは以下のようになります。
let num = textField.rx_text.map{ text -> String in print("map \(text)") return "*\(text)*" } num.bindTo(label1.rx_text).addDisposableTo(disposeBag) num.bindTo(label2.rx_text).addDisposableTo(disposeBag)
さて、このコードを早速実行してみましょう。
map map map 1 map 1 map 12 map 12
なんと、文字に変更を加えるたび、mapのクロージャー内の処理が2回ずつ実行されてしまっています。
今回の場合だと同じ加工を施した同じ内容を2つのラベルに表示させたいので、mapのクロージャー内の処理は1変更に対して1回だけ実行されればいいのですが・・・。
なぜこのようなことが起こってしまったのかというと、2つのオブジェクトにbindしsubscribeすると、別々の2本のストリームが生成されてしまうんだそうです。
このような性質を持つものを、Cold Observableと呼ぶようです。
今回のような軽い処理であれば大きな問題にはなりませんけど、重い処理だったり、ファイルIOや通信処理などが含まれていたりすると、それらが2回ずつ実行されると困りますよね。
shareReplayを使ってみる
ではどうすれば良いのかというと、Coldと呼ぶくらいですから、Hot Observableを使います。
Cold ObservableをHot Observableに変換してくれる「Hot変換オペレータ」というものがあるので、その中の1つである「shareReplay」を使います。
@akio0911 Hot変換オペレータの一つです。Hot/Coldの話を含めてこの辺が参考になると思います https://t.co/YzgAE0j652 https://t.co/4SZPuC9bt5
— Shinichiro Oba (@ooba) 2016年4月20日
let num = textField.rx_text .map{ text -> String in print("map \(text)") return "*\(text)*" } .shareReplay(1) num.bindTo(label1.rx_text).addDisposableTo(disposeBag) num.bindTo(label2.rx_text).addDisposableTo(disposeBag)
shareReplay(1)は、内部的にはreplay(1).refCountを呼び出してるだけのショートカットなんだそうですが、詳細についてはまた別記事を書こうと思います。
参考 : [RxSwift] shareReplayをちゃんと書いてお行儀良くストリームを購読しよう – Qiita
実行結果は以下のようになります。
map map 1 map 12 map 123
テキストフィールドへの1変更に対して、mapのクロージャー内の処理が1回ずつ呼ばれています。
これは、Hot Observerの「ストリームを分岐する性質」によるものだそうです。
@akio0911はこう思った。
Cold ObservableとHot Observableの違いが分かっていないと、意図せず無駄な処理が発生してしまいそうなので、ここは注意が必要ですね。
関連記事
この記事が気に入ったら「いいね!」しよう
Twitterで更新情報をゲット!