LoginSignup
2
3

More than 1 year has passed since last update.

【Swift】RxSwift勉強してみたPart9

Last updated at Posted at 2021-05-10

はじめに

前回
今回はOperatorをいくつか練習していきます

Operators

Filtering Operators

ignoreElements

onNextを無視する

let publishSubject = PublishSubject<String>()
let disposeBag = DisposeBag()
publishSubject
    .ignoreElements()
    .subscribe { _ in
        print("subscription is called")
    }
    .disposed(by: disposeBag)

publishSubject.onNext("1") // 呼ばれない
publishSubject.onNext("2") // 呼ばれない
publishSubject.onNext("3") // 呼ばれない
publishSubject.onCompleted() // "subscription is called"

element(at:)

指定した箇所のイベントを購読

let publishSubject = PublishSubject<String>()
publishSubject
    .element(at: 1)
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)

publishSubject.onNext("1")
publishSubject.onNext("2") // 2
publishSubject.onNext("3")

filter

条件に合うものだけを購読

Observable.of("aa", "bbb", "cccc", "ddddd", "eeeeee")
    .filter { $0.count > 3 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

//cccc
//ddddd
//eeeeee

skip

指定した要素の数だけイベントを飛ばす

Observable.of(1, 2, 3, 4, 5, 6)
    .skip(3)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

// 4
// 5
// 6

skip(while:)

条件に合うイベントまでスキップする

Observable.of(1, 1, 1, 2, 2, 2, 3, 3, 3)
    .skip(while: { $0 != 2 }) // 2じゃない間はとばし、2になったらそれ以降購読
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

// 2
// 2
// 2
// 3
// 3
// 3

skip(until: )

基準のイベントが流れてきたらそれ以降を購読

let trigger = PublishSubject<String>()
publishSubject.skip(until: trigger)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

publishSubject.onNext("1")
publishSubject.onNext("2")
trigger.onNext("X")
publishSubject.onNext("3")
publishSubject.onNext("4")

// 3
// 4

take

引数の数だけ、先頭から購読

Observable.of(1, 2, 3, 4, 5, 6)
    .take(3)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

// 1
// 2
// 3

take(while: )

条件に合う限り購読、一度でも条件を満た差なくなるとそれ以降購読しない

Observable.of(1, 2, 3, 4, 5, 6)
    .take(while: { $0 < 4 } )
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

// 1
// 2
// 3

take(until: )

引数に基準となるオブザーバブルを取り、それが購読されるまでのイベントを購読する

let trigger = PublishSubject<String>()
publishSubject
    .take(until: trigger)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

publishSubject.onNext("1")
publishSubject.onNext("2")
trigger.onNext("X")
publishSubject.onNext("3")
publishSubject.onNext("4")

// 1
// 2

Transforming Operators

toArray

配列にする

Observable.of(1, 2, 3, 4, 5)
    .toArray()
    .subscribe(onSuccess: { print($0) },
               onFailure: { print($0) },
               onDisposed: { print("onDisposed") }
    ).disposed(by: disposeBag)

// [1, 2, 3, 4, 5]
// onDisposed

map

全てのイベントを変換

Observable.of(1, 2, 3, 4, 5)
    .map { $0 * 10 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

//10
//20
//30
//40
//50

flatMap

map + mergeのようなイメージ

struct Student {
    var score: BehaviorRelay<Int>
}
let reon = Student(score: BehaviorRelay(value: 10))
let tom = Student(score: BehaviorRelay(value: 20))
let student = PublishSubject<Student>()
student.asObservable()
    .flatMap { $0.score.asObservable() }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

student.onNext(reon) // 10
reon.score.accept(100) // 100
tom.score.accept(200) // 200
student.onNext(tom) // 呼ばれない

flatMapLatest

map + switchLatest(次のObservableが来たらそちらを優先する)

struct Student {
    var score: BehaviorRelay<Int>
}
let reon = Student(score: BehaviorRelay(value: 10))
let tom = Student(score: BehaviorRelay(value: 20))
let student = PublishSubject<Student>()
student.asObservable()
    .flatMapLatest { $0.score.asObservable() }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

student.onNext(reon)
student.onNext(tom)
reon.score.accept(100)
tom.score.accept(200)

Combing Operators

startsWith

先頭のイベントを任意のものに変更できる

let numbers = Observable.of(2, 3, 4)
let observable = numbers.startWith(1)
observable
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
// 1
// 2
// 3
// 4

concat

Observableを結合できる

let first = Observable.of(1, 2, 3)
let second = Observable.of(4, 5, 6)
let observable = Observable.concat([first, second])
observable
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
// 1
// 2
// 3
// 4
// 5
// 6

merge

こちらもObservableを結合できますが、concatとの違いは、時系列順になるということです。

let left = PublishSubject<Int>()
let right = PublishSubject<Int>()
let source = Observable.of(left.asObservable(), right.asObservable())
let observable = source.merge()
observable
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

left.onNext(1)
left.onNext(2)
right.onNext(100)
left.onNext(3)
right.onNext(200)
right.onNext(300)

//1
//2
//100
//3
//200
//300

combineLatest

近い最新の値同士を組み合わせたイベントを作成

let left = PublishSubject<String>()
let right = PublishSubject<String>()
let observable = Observable.combineLatest(left, right) { lastLeft, lastRight in
    return lastLeft + lastRight
}
let disposable = observable.subscribe(onNext: { print($0) } )
left.onNext("A")
left.onNext("B")
right.onNext("1")
left.onNext("C")
right.onNext("2")
right.onNext("3")
left.onNext("D")
right.onNext("4")

// B1
// C1
// C2
// C3
// D3
// D4

withLatestFrom

任意のイベント発生時に、最新のイベントを発生させる。
今回は、ボタンを押した後に、テキストフィールドの最新のイベント(Swift)を流している。

let button = PublishSubject<Void>()
let textField = PublishSubject<String>()
let observable = button.withLatestFrom(textField)
let disposable = observable.subscribe(onNext: { print($0) })

textField.onNext("S")
textField.onNext("Sw")
textField.onNext("Swi")
textField.onNext("Swif")
textField.onNext("Swift") // これがtextFieldの最新の値
button.onNext(()) // ここで初めて呼ばれる
button.onNext(()) // ここでも呼ばれる

// Swift
// Swift

reduce

イベントを一つにまとめる加工を行う

let observable = Observable.of(1, 2, 3)
observable.reduce(0, accumulator: +)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

// 6

scan

reduceの時と違い、日々イベントを更新していく

let observable = Observable.of(1, 2, 3)
observable.scan(0, accumulator: +)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
// 1
// 3
// 6

おわりに

次回
他にもたくさん種類があるので、気になる方はマーブルダイアグラムを見てみてください!
マーブルダイアグラム

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3