18
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Organization

よく使いそうなRxSwiftのオペレーターの勉強をしてみた(flatMap, flatMapFirst, flatMapLatest 等)

Atrae Advent Calendar 2019 の10日目を担当するアガツマです。
普段は、ビジネス版マッチングアプリ yenta のiOS版を開発をしています。

私は今、RxSwiftの勉強をしています。
その中で、基礎となる一部のオペレーターの動作についてまとめてみました。
(まだ学習中で、理解が深くない部分もあるので間違っていたらコメントお願います!)

RxSwiftのオペレーターとは、Observableに用意されているイベントを加工する用のメソッドのことを指します

勉強をすすめる上で
オブザーバーパターンから始めるRxSwift入門
という記事がとても参考になったのでRxSwiftについて知りたい方はこちらも読んでみるのをオススメします。
(この記事では、マーブルダイアグラムをいきなり書いてしまっていますがこの記事に詳しい解説が載っています)

一般的なオペレーター(一部抜粋)

filter

処理
ある条件に合致するイベントだけ通知する。

用途
通知するイベントに条件をつけたい場合
(○文字以下だったら通知しない、イベントがtrueになった場合のみ通知したい)

コード

let observable = Observable.of(1, 10, 2, 9, 3, 8, 4, 7, 5, 6)
            .filter { $0 < 5 }
            .subscribe(onNext: {
                print("onNext: ", $0)
            })

出力結果

onNext:  1
onNext:  2
onNext:  3
onNext:  4

マーブルダイアグラム
スクリーンショット 2019-12-10 21.47.16.png

skip

処理
先頭から指定した数だけイベントを無視してスキップする。

用途
skip(1)を利用することで、最初の値を無視して、変化だけを検知するような場合に利用

コード

let observable = Observable.of(1, 2, 3, 4, 5)
            .skip(1)
            .subscribe(onNext: {
                print("onNext: ", $0)
            })

出力結果

onNext:  2
onNext:  3
onNext:  4
onNext:  5

マーブルダイアグラム
スクリーンショット 2019-12-10 21.50.01.png

map

処理
1つのObservableのイベントの要素を別の値に変換する。

用途
すべてのイベントに対して処理を適応したい場合
(すべての値を10倍したい、入力されてきた文字列をすべて小(大)文字で扱いたい)

コード

let observable = Observable.of(1,2,3,4,5,6)
            .map { $0 * 10 }
            .subscribe(onNext: {
                print("onNext: ", $0)
            })

出力結果

onNext:  10
onNext:  20
onNext:  30
onNext:  40
onNext:  50
onNext:  60

マーブルダイアグラム
スクリーンショット 2019-12-10 21.54.37.png

flatMap

処理
元のObservableのイベント毎に、Observableに変換して、そのObservableが発行するイベントを1つに集約する。

用途
非同期処理を扱いたい場合(API通信での画像の読み込み、異常系のアラート表示など)

コード
(解説)
1. A~Cの3つの大文字を通知するObservable<String>を作成
2. 1つ大文字にa~cの小文字をつけて通知するObservableを3つ作成しObservable<Observable<String>>を作成
3. それらのObsevableの通知内容を集約した Observable<String> に変換

let observable = Observable.of("A","B","C") // 1
        .flatMap { uppercaseChar in
            Observable.of(uppercaseChar + "a",uppercaseChar + "b",uppercaseChar + "c") // 2
        } // 3                                                                                   
        .subscribe(onNext: {                                                               
            print("onNext: ", $0)
        })

出力結果(非同期なので、結果は毎回変化します)

onNext:  Aa
onNext:  Ab
onNext:  Ba <- 非同期に処理が行われる
onNext:  Ac
onNext:  Bb
onNext:  Ca
onNext:  Bc
onNext:  Cb
onNext:  Cc

マーブルダイアグラム
スクリーンショット 2019-12-10 22.33.07.png

flatMapFirst

処理
イベントを Observable に変換し、常に1つの Observable のイベントしか通知しない。
前のflatMapでは、非同期処理が可能になり複数のObservableのイベントが1つに集約が可能だが、
flatMapFirstでは一度 Observable が発行されるとそれが完了するまで、他の Observable は無視する。(完了後は無視しない)

用途
既に処理中だったら、処理を開始しないという実装(loadingの表示など)

コード

let observable = Observable.of("A","B","C")
        .flatMapFirst { uppercaseChar in
                Observable.of(uppercaseChar + "a",uppercaseChar + "b",uppercaseChar + "c")
        }
        .subscribe(onNext: {                                                               
            print("onNext: ", $0)
        })

出力結果(非同期なので、結果は毎回変化します)

onNext:  Aa
onNext:  Ab
onNext:  Ac

マーブルダイアグラム
スクリーンショット 2019-12-11 10.53.34.png

flatMapLatest

これも flatMapFirst と同じくイベントを Observable に変換し、常に1つの Observable のイベントしか通知しないのですが、次の Observable が来るとそちらにスイッチします。
Observable に変換
常に一番新しい Observable を実行

処理
前のflatMapFirstと同じくイベントを Observable に変換し、常に1つの Observable のイベントしか通知しない。
新たな Observable が発行されると、前の Observable の完了を待たずに新しい方にスイッチする。(常に新しいObservableを実行)

用途
一番新しい処理結果を利用したいという実装(文字入力、API通信の結果表示など)

コード

let observable = Observable.of("A","B","C")
        .flatMapLatest { uppercaseChar in
                Observable.of(uppercaseChar + "a",uppercaseChar + "b",uppercaseChar + "c")
        }
        .subscribe(onNext: {
            print("onNext: ", $0)
        })

出力結果(非同期なので、結果は毎回変化します)

onNext:  Aa
onNext:  Ba
onNext:  Ca
onNext:  Cb
onNext:  Cc

マーブルダイアグラム
スクリーンショット 2019-12-10 23.12.28.png

おわりに

今回は、RxSwiftを書く上での基礎(のほんの一部)を学習しました。
その中でもflatMap, flatMapFirst, flatMapLatestの違いを理解し説明するのに時間がかかってしまいました。。。
他にも、複数のobservableを合成するオペレーター(merge, combineLatest, zip, withLatestFrom etc..)があるので次回はそちらをまとめてみようと思います!
Atrae Advent Calendar 2019 明日は、料理人からエンジニアに転身した@katou2213が書きます!
よろしくおねがいします!

参考

RxSwift研究読本1 入門編
ReactiveX Document

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
Sign upLogin
18
Help us understand the problem. What are the problem?