2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have 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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?