今天講講Combining operator,因為我們常常要合併多個Oberservable,藉此來獲得(分享)想要的資料,但Observable概念就像資料流,隨時間在走跳,所以依照情境來選擇operator是很重要的,Combining operator有好幾個,每個又都好重要,所以,我們分幾天介紹,附上範例,邊走邊講吧!
Combining operator有分為合併元素跟合併Observable,我們今天就先從合併元素的講起。
reduce
跟swift的reduce
用法相同,都是給定初始值,尋訪每個元素,去做累加的動作。
let subject = PublishSubject<Int>()
let observable = subject.reduce(0) { summary, newValue in
return summary + newValue
}
observable
.subscribe(onNext: { value in
print(value)
})
.disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(3)
subject.onNext(5)
subject.onNext(7)
subject.onNext(9)
subject.onCompleted()
執行結果
25
值得大家注意的一點是,reduce
會直到接收到.Completed
才會開始執行,並且,只會回傳最後的結果,這點要特別注意。
跟reduce
超像,差別在於.scan
不需要接收到.Completed
才執行
let subject = PublishSubject<Int>()
let observable = subject.scan(0) { summary, newValue in
return summary + newValue
}
observable
.subscribe(onNext: { value in
print(value)
})
.disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(3)
subject.onNext(5)
subject.onNext(7)
subject.onNext(9)
執行結果
1
4
9
16
25
所以,print
會將每一個步驟列印出,並且,不用收到.Completed
才執行,這是跟reduce
差異最大的地方,也因為這樣,通常情況下我也會使用scan
,相較之下比較靈活。
startWith
就像是簡單版的concat
,在Observable發送之前,給定一個預設值。
let subject = PublishSubject<Void>()
let observable = subject.asObservable().startWith(())
observable
.subscribe(onNext: {
print("Do something.")
})
.disposed(by: disposeBag)
執行結果
Do something.
在沒發出任何元素的狀況下,預先發了一個預設值。
大家有沒有想過,我就用 BehaviorSubject 帶預設值就好啊!為什麼要用startWith
?
這是我一開始學的疑惑,的確以上這情境達到的結果是一樣的,但概念上不一樣,BehaviorSubject概念是訂閱時可以拿到上一個值,startWith
就只是在最一開始發出一預設值,假設我們在程式後面加上
delay(1) {
observable
.subscribe(onNext: {
print("Do something. \($0)")
})
.disposed(by: self.disposeBag)
}
這個情境下,BehaviorSubject仍然可以拿到上一個元素,而startWith
卻拿不到,這時候結果就不一樣了。
我覺得這是Rx很妙的地方,你可能用錯operator程式當下也是好好的,但某個情境下就跑出問題,唯有瞭解每一個operator,依據情境去做選擇才是正解!
今天講了幾個Combine Element的operator,明天會繼續介紹Combine Observable,以上,明天見!