嗨嗨,今天第15天,已經超過一半了阿!今天繼續講Combining Observables。
zip
跟merge
和combineLatest
也很相似,不同在於發出的時機,zip
發出的時機是相同位置的元素一同發送,1st對應1st、2nd對應2nd、依此類推,當你需要兩個 resource(或多個)同時出現,那就選擇zip
了!
我們拿 combineLatest 範例,只將operator
換成zip
,來看看結果有什麼不同
let one = PublishSubject<String>()
let two = PublishSubject<Int>()
let result = Observable.zip(one, two) { str, number in
return "\(str), \(number)"
}
result
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
one.onNext("Koala")
two.onNext(2)
one.onNext("Penguin")
one.onNext("Monkey")
two.onNext(7)
執行結果
Koala, 2
Penguin, 7
Koala
跟數字2
都是Observable的第一個元素,所以被配再一起了Penguin
跟數字7
都是2nd,儘管中間還有Monkey
,也不會受影響("Koala", 2)
("Penguin", 7)
withLatestFrom
也是去合併最新的元素,就以這概念來說,跟combineLatest
有點像,但不同之處在於, withLatestFrom
是以一條Observable為主,去接收另一條Observable最新的值,常見情境就是button的tap事件去合併某Observable,藉此取的最新元素作為參數,再去呼叫 API,大概會像這樣
// ViewController
button.rx.tap.bind(to: viewModel.observer)
// ViewModel
let subject = PublishSubject<Void>()
observer = subject.asObserver()
subject.asObservable()
.withLatestFrom(neededData)
.flatMapLatest { API().request().asObservable().materialize() }
.share() // Void -> neededData Element
下面就先以簡單範例,來展示withLatestFrom
,因為怕有點難懂,我們在附上圖解。
let one = PublishSubject<String>()
let two = PublishSubject<Int>()
let result = one.withLatestFrom(two) { str, number in
return "\(str), \(number)"
}
result
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
one.onNext("Koala")
two.onNext(2)
one.onNext("Penguin")
one.onNext("Monkey")
two.onNext(7)
one.onNext("Chicken")
圖解如下
one
為主,當發出Koala的時候,這時會去合two
的最新元素,但two
還沒發出任何元素,所以這時並不會發生任何事情two
發出數字2
的時候,也不會發生任何事情Penguin
,這時會去合併two
的最新元素數字2
Monkey
,這時還是去合併two
的最新元素數字2
Chicken
,這時的two最新元素是數字7
,所以合併數字7
執行結果如下
Penguin, 2
Monkey, 2
Chicken, 7
RxSwift提供兩種方式來切換Observable,讓你在Run time的時候決定訂閱哪個Observable,第一個就是ambiguous,left.ambiguous(right)
會有兩個Observable,接著,只訂閱第一個發送元素的Observable,取消訂閱另一個,ambiguous意思就是曖昧、模棱兩可、歧義的,就好像一開始你也不知道你喜歡誰,但是當第一個跟你告白的你就會接受(?)
let one = PublishSubject<String>()
let two = PublishSubject<String>()
let result = one.amb(two)
result
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
one.onNext("A")
two.onNext("1")
one.onNext("B")
one.onNext("C")
two.onNext("2")
two.onNext("3")
執行結果
A
B
C
另外一個切換方式是switchLatest
,不像amb
,switchLatest
不侷限有只有兩條,要切換不同的Observable ,只要發送型態相同的Observable給Xource subject,就可以了,下面展示簡單範例
let one = PublishSubject<String>()
let two = PublishSubject<String>()
let three = PublishSubject<String>()
// 1
let source = PublishSubject<Observable<String>>()
// 2
source.switchLatest()
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
// 3
source.onNext(one)
one.onNext("A")
two.onNext("1")
three.onNext("Koala")
// 4
source.onNext(two)
one.onNext("B")
two.onNext("2")
one.onNext("Penguin")
source.onNext(three)
three.onNext("Monkey")
three.onNext("Chicken")
two.onNext("3")
Observable<T>
才行,這裡為Observable<String>
source.switchLatest()
,來查看現在切換到的Observable的元素one
時,現在只會接收one
發送過來的元素two
時,現在只會接收two
發送過來的元素,依此類推執行結果
A
2
Monkey
Chicken
講到這,switchLatest
跟flatMapLatest
很像啊?看書才知道原來flatMapLatest
就是map
跟switchLatest
的結合,不過我基本上我都是使用flatMapLatest
就是了。
大家會不會覺得,有幾個都好相似?
我一開始學的時候,flatLastest
、combineLatest
或withLatestFrom
都亂用,反正可以跑就好了(誤),明天會統整一下operator使用時機,跟大家分享我自己用錯的經驗,給大家做個參考,就這樣,掰掰