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
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
##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
flatMap
処理
元のObservableのイベント毎に、Observableに変換して、そのObservableが発行するイベントを1つに集約する。
用途
非同期処理を扱いたい場合(API通信での画像の読み込み、異常系のアラート表示など)
コード
(解説)
- A~Cの3つの大文字を通知する
Observable<String>
を作成 - 1つ大文字にa~cの小文字をつけて通知するObservableを3つ作成し
Observable<Observable<String>>
を作成 - それらの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
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
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
おわりに
今回は、RxSwiftを書く上での基礎(のほんの一部)を学習しました。
その中でもflatMap
, flatMapFirst
, flatMapLatest
の違いを理解し説明するのに時間がかかってしまいました。。。
他にも、複数のobservableを合成するオペレーター(merge, combineLatest, zip, withLatestFrom etc..)があるので次回はそちらをまとめてみようと思います!
Atrae Advent Calendar 2019 明日は、料理人からエンジニアに転身した@katou2213が書きます!
よろしくおねがいします!