RxSwift核心
1. Observable - 可被監(jiān)聽的序列
Observable 可以用于描述元素異步產(chǎn)生的序列傲茄。這樣我們生活中許多事物都可以通過它來表示: Observable<Double> 溫度
例如:你可以將溫度看作是一個(gè)序列劈猿,然后監(jiān)測這個(gè)溫度值,最后對這個(gè)值做出響應(yīng)庸蔼。例如:當(dāng)室溫高于 33 度時(shí),打開空調(diào)降溫
特征序列
- Single
Single 是 Observable 的另外一個(gè)版本贮匕。不像 Observable 可以發(fā)出多個(gè)元素姐仅,它要么只能發(fā)出一個(gè)元素,要么產(chǎn)生一個(gè) error 事件刻盐。
A.發(fā)出一個(gè)元素掏膏,或一個(gè) error 事件
B.不會共享狀態(tài)變化
- Completable
Completable 是 Observable 的另外一個(gè)版本。不像 Observable 可以發(fā)出多個(gè)元素敦锌,它要么只能產(chǎn)生一個(gè) completed 事件馒疹,要么產(chǎn)生一個(gè) error 事件。
A.發(fā)出零個(gè)元素
B.發(fā)出一個(gè) completed 事件或者一個(gè) error 事件
C.不會共享狀態(tài)變化
- Maybe
Maybe 是 Observable 的另外一個(gè)版本乙墙。它介于 Single 和 Completable 之間颖变,它要么只能發(fā)出一個(gè)元素生均,要么產(chǎn)生一個(gè) completed 事件,要么產(chǎn)生一個(gè) error 事件悼做。
A.發(fā)出一個(gè)元素或者一個(gè) completed 事件或者一個(gè) error 事件
B.不會共享狀態(tài)變化”
- Driver
Driver(司機(jī)疯特?) 是一個(gè)精心準(zhǔn)備的特征序列。它主要是為了簡化 UI 層的代碼肛走。不過如果你遇到的序列具有以下特征漓雅,你也可以使用它:
A.不會產(chǎn)生 error 事件
B.一定在 MainScheduler 監(jiān)聽(主線程監(jiān)聽)
C.共享狀態(tài)變化
*ControlEvent
ControlEvent 專門用于描述 UI 控件所產(chǎn)生的事件,它具有以下特征:
A.不會產(chǎn)生 error 事件
B.一定在 MainScheduler 訂閱(主線程訂閱)
C.一定在 MainScheduler 監(jiān)聽(主線程監(jiān)聽)
D.共享狀態(tài)變化
2. Observer - 觀察者
觀察者 是用來監(jiān)聽事件朽色,然后它需要這個(gè)事件做出響應(yīng)邻吞。例如:彈出提示框就是觀察者,它對點(diǎn)擊按鈕這個(gè)事件做出響應(yīng)葫男。
例如:當(dāng)室溫高于 33 度時(shí)抱冷,打開空調(diào)降溫
打開空調(diào)降溫就是觀察者 Observer<Double>。
創(chuàng)建觀察者:
創(chuàng)建觀察者最直接的方法就是在 Observable 的 subscribe 方法后面描述梢褐,事件發(fā)生時(shí)旺遮,需要如何做出響應(yīng)。而觀察者就是由后面的 onNext盈咳,onError耿眉,onCompleted的這些閉包構(gòu)建出來的。
特征觀察者
- AnyObserver
AnyObserver 可以用來描敘任意一種觀察者
*Binder
Binder 主要有以下兩個(gè)特征:
A.不會處理錯(cuò)誤事件
B.確保綁定都是在給定 Scheduler 上執(zhí)行(默認(rèn) MainScheduler)
一旦產(chǎn)生錯(cuò)誤事件鱼响,在調(diào)試環(huán)境下將執(zhí)行 fatalError鸣剪,在發(fā)布環(huán)境下將打印錯(cuò)誤信息。
let observer: AnyObserver<Bool> = AnyObserver { [weak self] (event) in
switch event {
case .next(let isHidden):
self?.usernameValidOutlet.isHidden = isHidden
default:
break
}
}
//observer
usernameValid.bind(to: observer).disposed(by: disposeBag)
extension Reactive where Base: UIView {
public var isHidden: Binder<Bool> {
return Binder(self.base) { view, hidden in
view.isHidden = hidden
}
}
}
usernameValid.bind(to: usernameValidOutlet.rx.isHidden).disposed(by: disposeBag)
3. Observable & Observer 既是可被監(jiān)聽的序列也是觀察者
在我們所遇到的事物中丈积,有一部分非常特別筐骇。它們既是可被監(jiān)聽的序列也是觀察者。
例如:textField的當(dāng)前文本江滨。它可以看成是由用戶輸入铛纬,而產(chǎn)生的一個(gè)文本序列。也可以是由外部文本序列唬滑,來控制當(dāng)前顯示內(nèi)容的觀察者:
// 作為可被監(jiān)聽的序列
let observable = textField.rx.text
observable.subscribe(onNext: { text in show(text: text) })
// 作為觀察者
let observer = textField.rx.text
let text: Observable<String?> = ...
text.bind(to: observer)
Subject
*AsyncSubject
AsyncSubject 將在源 Observable 產(chǎn)生完成事件后饺鹃,發(fā)出最后一個(gè)元素(僅僅只有最后一個(gè)元素),如果源 Observable 沒有發(fā)出任何元素间雀,只有一個(gè)完成事件悔详。那 AsyncSubject 也只有一個(gè)完成事件。
它會對隨后的觀察者發(fā)出最終元素惹挟。如果源 Observable 因?yàn)楫a(chǎn)生了一個(gè) error 事件而中止茄螃, AsyncSubject 就不會發(fā)出任何元素,而是將這個(gè) error 事件發(fā)送出來连锯。
let disposeBag = DisposeBag()
let subject = AsyncSubject<String>()
subject
.subscribe { print("Subscription: 1 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("??")
subject.onNext("??")
subject.onNext("??")
subject.onCompleted()
輸出結(jié)果:
Subscription: 1 Event: next(??)
Subscription: 1 Event: completed
*PublishSubject
PublishSubject 將對觀察者發(fā)送訂閱后產(chǎn)生的元素归苍,而在訂閱前發(fā)出的元素將不會發(fā)送給觀察者用狱。如果你希望觀察者接收到所有的元素,你可以通過使用Observable 的 create 方法來創(chuàng)建 Observable拼弃,或者使用 ReplaySubject夏伊。
如果源 Observable 因?yàn)楫a(chǎn)生了一個(gè) error 事件而中止, PublishSubject 就不會發(fā)出任何元素吻氧,而是將這個(gè) error 事件發(fā)送出來溺忧。
let disposeBag = DisposeBag()
let subject = PublishSubject<String>()
subject
.subscribe { print("Subscription: 1 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("??")
subject.onNext("??")
subject
.subscribe { print("Subscription: 2 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("???")
subject.onNext("???")
輸出結(jié)果:
Subscription: 1 Event: next(??)
Subscription: 1 Event: next(??)
Subscription: 1 Event: next(???)
Subscription: 2 Event: next(???)
Subscription: 1 Event: next(???)
Subscription: 2 Event: next(???)
*ReplaySubject
ReplaySubject 將對觀察者發(fā)送全部的元素,無論觀察者是何時(shí)進(jìn)行訂閱的盯孙。
這里存在多個(gè)版本的 ReplaySubject鲁森,有的只會將最新的 n 個(gè)元素發(fā)送給觀察者,有的只會將限制時(shí)間段內(nèi)最新的元素發(fā)送給觀察者振惰。
如果把 ReplaySubject 當(dāng)作觀察者來使用歌溉,注意不要在多個(gè)線程調(diào)用 onNext, onError 或 onCompleted。這樣會導(dǎo)致無序調(diào)用骑晶,將造成意想不到的結(jié)果痛垛。
let disposeBag = DisposeBag()
let subject = ReplaySubject<String>.create(bufferSize: 1)
subject
.subscribe { print("Subscription: 1 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("??")
subject.onNext("??")
subject
.subscribe { print("Subscription: 2 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("???")
subject.onNext("???")
輸出結(jié)果:
Subscription: 1 Event: next(??)
Subscription: 1 Event: next(??)
Subscription: 2 Event: next(??)
Subscription: 1 Event: next(???)
Subscription: 2 Event: next(???)
Subscription: 1 Event: next(???)
Subscription: 2 Event: next(???)
*BehaviorSubject
當(dāng)觀察者對 BehaviorSubject 進(jìn)行訂閱時(shí),它會將源 Observable 中最新的元素發(fā)送出來(如果不存在最新的元素桶蛔,就發(fā)出默認(rèn)元素)匙头。然后將隨后產(chǎn)生的元素發(fā)送出來。如果源 Observable 因?yàn)楫a(chǎn)生了一個(gè) error 事件而中止羽圃, BehaviorSubject 就不會發(fā)出任何元素,而是將這個(gè) error 事件發(fā)送出來
let disposeBag = DisposeBag()
let subject = BehaviorSubject(value: "??")
subject
.subscribe { print("Subscription: 1 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("??")
subject.onNext("??")
subject
.subscribe { print("Subscription: 2 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("???")
subject.onNext("???")
subject
.subscribe { print("Subscription: 3 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("??")
subject.onNext("??")
輸出結(jié)果:
Subscription: 1 Event: next(??)
Subscription: 1 Event: next(??)
Subscription: 1 Event: next(??)
Subscription: 2 Event: next(??)
Subscription: 1 Event: next(???)
Subscription: 2 Event: next(???)
Subscription: 1 Event: next(???)
Subscription: 2 Event: next(???)
Subscription: 3 Event: next(???)
Subscription: 1 Event: next(??)
Subscription: 2 Event: next(??)
Subscription: 3 Event: next(??)
Subscription: 1 Event: next(??)
Subscription: 2 Event: next(??)
Subscription: 3 Event: next(??)
Variable
在 Swift 中我們經(jīng)常會用 var 關(guān)鍵字來聲明變量抖剿。RxSwift 提供的 Variable 實(shí)際上是 var 的 Rx 版本朽寞,你可以將它看作是 RxVar。
我們來對比一下 var 以及 Variable 的用法:
使用 var:
// 在 ViewController 中
var model: Model? = nil {
didSet { updateUI(with: model) }
func updateUI(with model: Model?) { ... }
let model: Variable<Model?> = Variable(nil)
override func viewDidLoad() {
super.viewDidLoad()
model.asObservable()
.subscribe(onNext: { [weak self] model in
self?.updateUI(with: model)
})
.disposed(by: disposeBag)
func updateUI(with model: Model?) { ... }
func getModel() -> Model { ... }
第一種使用 var 的方式十分常見斩郎,在 ViewController 中監(jiān)聽 Model 的變化脑融,然后刷新頁面。
第二種使用 Variable 則是 RxSwift 獨(dú)有的缩宜。Variable 幾乎提供了 var 的所有功能肘迎。另外,加上一條非常重要的特性锻煌,就是可以通過調(diào)用 asObservable() 方法轉(zhuǎn)換成序列妓布。然后你可以對這個(gè)序列應(yīng)用操作符,來合成其他的序列宋梧。所以匣沼,如果我們聲明的變量需要提供 Rx 支持,那就選用 Variable 這個(gè)類型捂龄。
說明
Variable 封裝了一個(gè) BehaviorSubject释涛,所以它會持有當(dāng)前值加叁,并且 Variable 會對新的觀察者發(fā)送當(dāng)前值。它不會產(chǎn)生 error 事件唇撬。Variable 在 deinit 時(shí)它匕,會發(fā)出一個(gè) completed 事件
Operator - 操作符
操作符可以幫助大家創(chuàng)建新的序列,或者變化組合原有的序列窖认,從而生成一個(gè)新的序列豫柬。
我們之前在輸入驗(yàn)證例子中就多次運(yùn)用到操作符。例如耀态,通過 map 方法將輸入的用戶名轮傍,轉(zhuǎn)換為用戶名是否有效。然后用這個(gè)轉(zhuǎn)化后來的序列來控制紅色提示語是否隱藏首装。我們還通過 combineLatest 方法创夜,將用戶名是否有效和密碼是否有效合并成兩者是否同時(shí)有效。然后用這個(gè)合成后來的序列來控制按鈕是否可點(diǎn)擊仙逻。
這里 map 和 combineLatest 都是操作符驰吓,它們可以幫助我們構(gòu)建所需要的序列。現(xiàn)在系奉,我們再來看幾個(gè)例子:
Filter:
Map:
5. Disposable - 可被清除的資源
Disposable - 可被清除的資源
通常來說圈盔,一個(gè)序列如果發(fā)出了 error 或者 completed 事件匪蝙,那么所有內(nèi)部資源都會被釋放。如果你需要提前釋放這些資源或取消訂閱的話,那么你可以對返回的 可被清除的資源(Disposable) 調(diào)用 dispose 方法:
var disposable: Disposable?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.disposable = textField.rx.text.orEmpty
.subscribe(onNext: { text in print(text) })
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.disposable?.dispose()
}
調(diào)用 dispose 方法后沿腰,訂閱將被取消,并且內(nèi)部資源都會被釋放厌漂。通常情況下槽地,你是不需要手動調(diào)用 dispose 方法的。我們推薦使用 清除包(DisposeBag) 或者 takeUntil 操作符 來管理訂閱的生命周期并鸵。
DisposeBag - 清除包
因?yàn)槲覀冇玫氖?Swift 鸳粉,所以我們更習(xí)慣于使用 ARC 來管理內(nèi)存。那么我們能不能用 ARC 來管理訂閱的生命周期了园担。答案是肯定了届谈,你可以用 清除包(DisposeBag) 來實(shí)現(xiàn)這種訂閱管理機(jī)制
var disposeBag = DisposeBag()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
textField.rx.text.orEmpty
.subscribe(onNext: { text in print(text) })
.disposed(by: self.disposeBag)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.disposeBag = DisposeBag()
}
當(dāng) 清除包 被釋放的時(shí)候,清除包 內(nèi)部所有 可被清除的資源(Disposable) 都將被清除弯汰。
takeUntil
另外一種實(shí)現(xiàn)自動取消訂閱的方法就是使用 takeUntil 操作符艰山,上面那個(gè)輸入驗(yàn)證的演示代碼也可以通過使用 takeUntil 來實(shí)現(xiàn):
override func viewDidLoad() {
“super.viewDidLoad()
...
_ = usernameValid
.takeUntil(self.rx.deallocated)
.bind(to: passwordOutlet.rx.isEnabled)
_ = usernameValid
.takeUntil(self.rx.deallocated)
.bind(to: usernameValidOutlet.rx.isHidden)
_ = passwordValid
.takeUntil(self.rx.deallocated)
.bind(to: passwordValidOutlet.rx.isHidden)
_ = everythingValid
.takeUntil(self.rx.deallocated)
.bind(to: doSomethingOutlet.rx.isEnabled)
}
這將使得訂閱一直持續(xù)到控制器的 dealloc 事件產(chǎn)生為止。
6. Schedulers - 調(diào)度器
Schedulers 是 Rx 實(shí)現(xiàn)多線程的核心模塊咏闪,它主要用于控制任務(wù)在哪個(gè)線程或隊(duì)列運(yùn)行程剥。
let rxData: Observable<Data> = ...
rxData.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] data in
self?.data = data
})
.disposed(by: disposeBag)
使用 subscribeOn
我們用 subscribeOn 來決定數(shù)據(jù)序列的構(gòu)建函數(shù)在哪個(gè) Scheduler 上運(yùn)行。以上例子中,由于獲取 Data 需要花很長的時(shí)間织鲸,所以用 subscribeOn 切換到 后臺 Scheduler 來獲取 Data舔腾。這樣可以避免主線程被阻塞。
使用 observeOn
我們用 observeOn 來決定在哪個(gè) Scheduler 監(jiān)聽這個(gè)數(shù)據(jù)序列搂擦。以上例子中稳诚,通過使用 observeOn 方法切換到主線程來監(jiān)聽并且處理結(jié)果。
一個(gè)比較典型的例子就是瀑踢,在后臺發(fā)起網(wǎng)絡(luò)請求扳还,然后解析數(shù)據(jù),最后在主線程刷新頁面橱夭。你就可以先用 subscribeOn 切到后臺去發(fā)送請求并解析數(shù)據(jù)氨距,最后用 observeOn 切換到主線程更新頁面。
MainScheduler
MainScheduler 代表主線程棘劣。如果你需要執(zhí)行一些和 UI 相關(guān)的任務(wù)俏让,就需要切換到該 Scheduler 運(yùn)行。
SerialDispatchQueueScheduler
SerialDispatchQueueScheduler 抽象了竄行 DispatchQueue茬暇。如果你需要執(zhí)行一些竄行任務(wù)首昔,可以切換到這個(gè) Scheduler 運(yùn)行。
ConcurrentDispatchQueueScheduler
ConcurrentDispatchQueueScheduler 抽象了并行 DispatchQueue糙俗。如果你需要執(zhí)行一些并發(fā)任務(wù)勒奇,可以切換到這個(gè) Scheduler 運(yùn)行。
OperationQueueScheduler
OperationQueueScheduler 抽象了 NSOperationQueue巧骚。
它具備 NSOperationQueue 的一些特點(diǎn)赊颠,例如,你可以通過設(shè)置 maxConcurrentOperationCount劈彪,來控制同時(shí)執(zhí)行并發(fā)任務(wù)的最大數(shù)量竣蹦。
7. Error Handling - 錯(cuò)誤處理
一旦序列里面產(chǎn)出了一個(gè) error 事件,整個(gè)序列將被終止粉臊。RxSwift 主要有兩種錯(cuò)誤處理機(jī)制:
- retry - 重試
- catch - 恢復(fù)
retry - 重試
retry 可以讓序列在發(fā)生錯(cuò)誤后重試:
// 請求 JSON 失敗時(shí)草添,立即重試驶兜,
// 重試 3 次后仍然失敗扼仲,就將錯(cuò)誤拋出
let rxJson: Observable<JSON> = ...
rxJson
.retry(3)
.subscribe(onNext: { json in
print("取得 JSON 成功: \(json)")
}, onError: { error in
print("取得 JSON 失敗: \(error)")
})
.disposed(by: disposeBag)
以上的代碼非常直接 retry(3) 就是當(dāng)發(fā)生錯(cuò)誤時(shí),就進(jìn)行重試操作抄淑,并且最多重試 3 次
retryWhen
如果我們需要在發(fā)生錯(cuò)誤時(shí)屠凶,經(jīng)過一段延時(shí)后重試,那可以這樣實(shí)現(xiàn):
let retryDelay: Double = 5 // 重試延時(shí) 5 秒
rxJson
.retryWhen { (rxError: Observable<Error>) -> Observable<Int> in
return Observable.timer(retryDelay, scheduler: MainScheduler.instance)
}
.subscribe(...)
.disposed(by: disposeBag)
這里我們需要用到 retryWhen 操作符肆资,這個(gè)操作符主要描述應(yīng)該在何時(shí)重試矗愧,并且通過閉包里面返回的 Observable 來控制重試的時(shí)機(jī):
閉包里面的參數(shù)是 Observable<Error> 也就是所產(chǎn)生錯(cuò)誤的序列,然后返回值是一個(gè) Observable。當(dāng)這個(gè)返回的Observable 發(fā)出一個(gè)元素時(shí)唉韭,就進(jìn)行重試操作夜涕。當(dāng)它發(fā)出一個(gè) error 或者 completed 事件時(shí),就不會重試属愤,并且將這個(gè)事件傳遞給到后面的觀察者女器。
如果需要加上一個(gè)最大重試次數(shù)的限制:
// 請求 JSON 失敗時(shí),等待 5 秒后重試住诸,
// 重試 4 次后仍然失敗驾胆,就將錯(cuò)誤拋出
let maxRetryCount = 4 // 最多重試 4 次
let retryDelay: Double = 5 // 重試延時(shí) 5 秒
rxJson
.retryWhen { (rxError: Observable<Error>) -> Observable<Int> in
return rxError.flatMapWithIndex { (error, index) -> Observable<Int> in
guard index < maxRetryCount else {
return Observable.error(error)
}
return Observable<Int>.timer(retryDelay, scheduler: MainScheduler.instance)
}
}
.subscribe(...)
.disposed(by: disposeBag)
我們用 flatMapWithIndex 這個(gè)操作符,因?yàn)樗梢越o我們提供錯(cuò)誤的索引數(shù) index贱呐。然后用這個(gè)索引數(shù)判斷是否超過最大重試數(shù)丧诺,如果超過了,就將錯(cuò)誤拋出奄薇。如果沒有超過驳阎,就等待 5 秒后重試。
catchError - 恢復(fù)
catchError 可以在錯(cuò)誤產(chǎn)生時(shí)惕艳,用一個(gè)備用元素或者一組備用元素將錯(cuò)誤替換掉:
searchBar.rx.text.orEmpty
...
.flatMapLatest { query -> Observable<[Repository]> in
...
return searchGitHub(query)
.catchErrorJustReturn([])
}
...
.bind(to: ...)
.disposed(by: disposeBag)
我們開頭的 Github 搜索就用到了catchErrorJustReturn搞隐。當(dāng)錯(cuò)誤產(chǎn)生時(shí),就返回一個(gè)空數(shù)組远搪,于是就會顯示一個(gè)空列表頁劣纲。
你也可以使用 catchError,當(dāng)錯(cuò)誤產(chǎn)生時(shí)谁鳍,將錯(cuò)誤事件替換成一個(gè)備選序列:
// 先從網(wǎng)絡(luò)獲取數(shù)據(jù)癞季,如果獲取失敗了,就從本地緩存獲取數(shù)據(jù)
let rxData: Observable<Data> = ... // 網(wǎng)絡(luò)請求的數(shù)據(jù)
let cahcedData: Observable<Data> = ... // 之前本地緩存的數(shù)據(jù)
rxData
.catchError { _ in cahcedData }
.subscribe(onNext: { date in
print("獲取數(shù)據(jù)成功: \(date.count)")
})
.disposed(by: disposeBag)
常用操作符
-
catchError
從一個(gè)錯(cuò)誤事件中恢復(fù)倘潜,將錯(cuò)誤事件替換成一個(gè)備選序列
catchError 操作符將會攔截一個(gè) error 事件绷柒,將它替換成其他的元素或者一組元素,然后傳遞給觀察者涮因。這樣可以使得 Observable 正常結(jié)束废睦,或者根本都不需要結(jié)束。
let disposeBag = DisposeBag()
let sequenceThatFails = PublishSubject<String>()
let recoverySequence = PublishSubject<String>()
sequenceThatFails
.catchError {
print("Error:", $0)
return recoverySequence
}
.subscribe { print($0) }
.disposed(by: disposeBag)
sequenceThatFails.onNext("??")
sequenceThatFails.onNext("??")
sequenceThatFails.onNext("??")
sequenceThatFails.onNext("??")
sequenceThatFails.onError(TestError.test)
recoverySequence.onNext("??")
輸出結(jié)果:
next(??)
next(??)
next(??)
next(??)
Error: test
next(??)
- catchErrorJustReturn
catchErrorJustReturn 操作符會將error 事件替換成其他的一個(gè)元素养泡,然后結(jié)束該序列嗜湃。
let disposeBag = DisposeBag()
let sequenceThatFails = PublishSubject<String>()
sequenceThatFails
.catchErrorJustReturn("??")
.subscribe { print($0) }
.disposed(by: disposeBag)
sequenceThatFails.onNext("??")
sequenceThatFails.onNext("??")
sequenceThatFails.onNext("??")
sequenceThatFails.onNext("??")
sequenceThatFails.onError(TestError.test)
輸出結(jié)果:
next(??)
next(??)
next(??)
next(??)
next(??)
completed
- combineLatest
當(dāng)多個(gè) Observables 中任何一個(gè)發(fā)出一個(gè)元素,就發(fā)出一個(gè)元素澜掩。這個(gè)元素是由這些 Observables 中最新的元素购披,通過一個(gè)函數(shù)組合起來的
combineLatest 操作符將多個(gè) Observables 中最新的元素通過一個(gè)函數(shù)組合起來,然后將這個(gè)組合的結(jié)果發(fā)出來肩榕。這些源 Observables 中任何一個(gè)發(fā)出一個(gè)元素刚陡,他都會發(fā)出一個(gè)元素(前提是,這些 Observables 曾經(jīng)發(fā)出過元素)。
let disposeBag = DisposeBag()
let first = PublishSubject<String>()
let second = PublishSubject<String>()
Observable.combineLatest(first, second) { $0 + $1 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
first.onNext("1")
second.onNext("A")
first.onNext("2")
second.onNext("B")
second.onNext("C")
second.onNext("D")
first.onNext("3")
first.onNext("4")
輸出結(jié)果:
1A
2A
2B
2C
2D
3D
4D
- concat
讓兩個(gè)或多個(gè) Observables 按順序串連起來
concat 操作符將多個(gè) Observables 按順序串聯(lián)起來筐乳,當(dāng)前一個(gè) Observable 元素發(fā)送完畢后歌殃,后一個(gè) Observable 才可以開始發(fā)出元素。
concat 將等待前一個(gè) Observable 產(chǎn)生完成事件后蝙云,才對后一個(gè) Observable 進(jìn)行訂閱挺份。如果后一個(gè)是“熱” Observable ,在它前一個(gè) Observable 產(chǎn)生完成事件前贮懈,所產(chǎn)生的元素將不會被發(fā)送出來匀泊。
startWith 和它十分相似。但是startWith不是在后面添加元素朵你,而是在前面插入元素各聘。
merge 和它也是十分相似。merge并不是將多個(gè) Observables 按順序串聯(lián)起來抡医,而是將他們合并到一起躲因,不需要 Observables 按先后順序發(fā)出元素。
let disposeBag = DisposeBag()
let subject1 = BehaviorSubject(value: "??")
let subject2 = BehaviorSubject(value: "??")
let variable = Variable(subject1)
variable.asObservable()
.concat()
.subscribe { print($0)
}.disposed(by: disposeBag)
subject1.onNext("??")
subject1.onNext("??")
variable.value = subject2
subject2.onNext("I would be ignored")
subject2.onNext("??")
subject1.onCompleted()
subject2.onNext("??")
輸出結(jié)果:
next(??)
next(??)
next(??)
next(??)
next(??)
- concatMap
將 Observable 的元素轉(zhuǎn)換成其他的 Observable忌傻,然后將這些 Observables 串連起來
concatMap 操作符將源 Observable 的每一個(gè)元素應(yīng)用一個(gè)轉(zhuǎn)換方法大脉,將他們轉(zhuǎn)換成 Observables。然后讓這些 Observables 按順序的發(fā)出元素水孩,當(dāng)concatMap 操作符將源 Observable 的每一個(gè)元素應(yīng)用一個(gè)轉(zhuǎn)換方法镰矿,將他們轉(zhuǎn)換成 Observables。然后讓這些 Observables 按順序的發(fā)出元素俘种,當(dāng)前一個(gè) Observable 元素發(fā)送完畢后秤标,后一個(gè) Observable 才可以開始發(fā)出元素。等待前一個(gè) Observable 產(chǎn)生完成事件后宙刘,才對后一個(gè) Observable 進(jìn)行訂閱苍姜。
let disposeBag = DisposeBag()
let subject1 = BehaviorSubject(value: "??")
let subject2 = BehaviorSubject(value: "??")
let variable = Variable(subject1)
variable.asObservable()
.concatMap { $0 }
.subscribe { print($0) }
.disposed(by: disposeBag)
subject1.onNext("??")
subject1.onNext("??")
variable.value = subject2
subject2.onNext("I would be ignored")
subject2.onNext("??")
subject1.onCompleted()
subject2.onNext("??")
輸出結(jié)果:
next(??)
next(??)
next(??)
next(??)
next(??)
- connect
通知可被連接的 Observable 可以開始發(fā)出元素了
可被連接的 Observable 和普通的 Observable 十分相似,不過在被訂閱后不會發(fā)出元素悬包,直到 connect 操作符被應(yīng)用為止衙猪。這樣一來你可以等所有觀察者全部訂閱完成后,才發(fā)出元素布近。
- create
通過一個(gè)構(gòu)建函數(shù)完整的創(chuàng)建一個(gè) Observable
create 操作符將創(chuàng)建一個(gè) Observable垫释,你需要提供一個(gè)構(gòu)建函數(shù),在構(gòu)建函數(shù)里面描述事件(next吊输,error饶号,completed)的產(chǎn)生過程铁追。
通常情況下一個(gè)有限的序列季蚂,只會調(diào)用一次觀察者的 onCompleted 或者 onError 方法。并且在調(diào)用它們后,不會再去調(diào)用觀察者的其他方法扭屁。
創(chuàng)建一個(gè) [0, 1, ... 8, 9] 的序列:
let id = Observable<Int>.create { observer in
observer.onNext(0)
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onNext(4)
observer.onNext(5)
observer.onNext(6)
observer.onNext(7)
observer.onNext(8)
observer.onNext(9)
observer.onCompleted()
return Disposables.create()
}
- debug
打印所有的訂閱算谈,事件以及銷毀信息
let disposeBag = DisposeBag()
let sequence = Observable<String>.create { observer in
observer.onNext("??")
observer.onNext("??")
observer.onCompleted()
return Disposables.create()
}
sequence
.debug("Fruit")
.subscribe()
.disposed(by: disposeBag)
輸出結(jié)果:
2017-11-06 20:49:43.187: Fruit -> subscribed
2017-11-06 20:49:43.188: Fruit -> Event next(??)
2017-11-06 20:49:43.188: Fruit -> Event next(??)
2017-11-06 20:49:43.188: Fruit -> Event completed
2017-11-06 20:49:43.189: Fruit -> isDisposed
- delay
將 Observable 的每一個(gè)元素拖延一段時(shí)間后發(fā)出
delay 操作符將修改一個(gè) Observable,它會將 Observable 的所有元素都拖延一段設(shè)定好的時(shí)間料滥, 然后才將它們發(fā)送出來然眼。
- delaySubscription
進(jìn)行延時(shí)訂閱
delaySubscription 操作符將在經(jīng)過所設(shè)定的時(shí)間后,才對 Observable 進(jìn)行訂閱操作葵腹。
- distinctUntilChanged
阻止 Observable 發(fā)出相同的元素
distinctUntilChanged 操作符將阻止 Observable 發(fā)出相同的元素高每。如果后一個(gè)元素和前一個(gè)元素是相同的,那么這個(gè)元素將不會被發(fā)出來践宴。如果后一個(gè)元素和前一個(gè)元素不相同鲸匿,那么這個(gè)元素才會被發(fā)出來。
let disposeBag = DisposeBag()
Observable.of("??", "??", "??", "??", "??", "??", "??")
.distinctUntilChanged()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
輸出結(jié)果:
??
??
??
??
??
- elementAt
只發(fā)出 Observable 中的第 n 個(gè)元素
elementAt 操作符將拉取 Observable 序列中指定索引數(shù)的元素阻肩,然后將它作為唯一的元素發(fā)出带欢。
let disposeBag = DisposeBag()
Observable.of("??", "??", "??", "??", "??", "??")
.elementAt(3)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
輸出結(jié)果:
??
- empty
創(chuàng)建一個(gè)空 Observable
empty 操作符將創(chuàng)建一個(gè) Observable,這個(gè) Observable 只有一個(gè)完成事件烤惊。
//創(chuàng)建一個(gè)空 Observable:
let id = Observable<Int>.empty()
//它相當(dāng)于:
let id = Observable<Int>.create { observer in
observer.onCompleted()
return Disposables.create()
}
- error
創(chuàng)建一個(gè)只有 error 事件的 Observable
error 操作符將創(chuàng)建一個(gè) Observable乔煞,這個(gè) Observable 只會產(chǎn)生一個(gè) error 事件。
//創(chuàng)建一個(gè)只有 error 事件的 Observable:
let error: Error = ...
let id = Observable<Int>.error(error)
//它相當(dāng)于:
let error: Error = ...
let id = Observable<Int>.create { observer in
observer.onError(error)
return Disposables.create()
}
- filter
僅僅發(fā)出 Observable 中通過判定的元素
filter 操作符將通過你提供的判定方法過濾一個(gè) Observable柒室。
let disposeBag = DisposeBag()
Observable.of(2, 30, 22, 5, 60, 1)
.filter { $0 > 10 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
輸出結(jié)果:
30
22
60
- flatMap
將 Observable 的元素轉(zhuǎn)換成其他的 Observable渡贾,然后將這些 Observables 合并
flatMap 操作符將源 Observable 的每一個(gè)元素應(yīng)用一個(gè)轉(zhuǎn)換方法,將他們轉(zhuǎn)換成 Observables雄右。 然后將這些 Observables 的元素合并之后再發(fā)送出來剥啤。
這個(gè)操作符是非常有用的,例如不脯,當(dāng) Observable 的元素本生擁有其他的 Observable 時(shí)府怯,你可以將所有子 Observables 的元素發(fā)送出來。
let disposeBag = DisposeBag()
let first = BehaviorSubject(value: "????")
let second = BehaviorSubject(value: "???")
let variable = Variable(first)
variable.asObservable()
.flatMap { $0 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
first.onNext("??")
variable.value = second
second.onNext("???")
first.onNext("??")
輸出結(jié)果:
????
??
???
???
??
- flatMapLatest
將 Observable 的元素轉(zhuǎn)換成其他的 Observable防楷,然后取這些 Observables 中最新的一個(gè)
flatMapLatest 操作符將源 Observable 的每一個(gè)元素應(yīng)用一個(gè)轉(zhuǎn)換方法牺丙,將他們轉(zhuǎn)換成 Observables。一旦轉(zhuǎn)換出一個(gè)新的 Observable复局,就只發(fā)出它的元素冲簿,舊的 Observables 的元素將被忽略掉。
tips:與 flatMap 比較更容易理解
let disposeBag = DisposeBag()
let first = BehaviorSubject(value: "????")
let second = BehaviorSubject(value: "???")
let variable = Variable(first)
variable.asObservable()
.flatMapLatest { $0 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
first.onNext("??")
variable.value = second
second.onNext("???")
first.onNext("??")
輸出結(jié)果:
????
??
???
???
- from
將其他類型或者數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為 Observable
當(dāng)你在使用 Observable 時(shí)亿昏,如果能夠直接將其他類型轉(zhuǎn)換為 Observable峦剔,這將是非常省事的。from 操作符就提供了這種功能角钩。
//將一個(gè)數(shù)組轉(zhuǎn)換為 Observable:
let numbers = Observable.from([0, 1, 2])
//它相當(dāng)于:
let numbers = Observable<Int>.create { observer in
observer.onNext(0)
observer.onNext(1)
observer.onNext(2)
observer.onCompleted()
return Disposables.create()
}
//將一個(gè)可選值轉(zhuǎn)換為 Observable
let optional: Int? = 1
let value = Observable.from(optional: optional)
//它相當(dāng)于:
let optional: Int? = 1
let value = Observable<Int>.create { observer in
if let element = optional {
observer.onNext(element)
}
observer.onCompleted()
return Disposables.create()
}
- just
創(chuàng)建 Observable 發(fā)出唯一的一個(gè)元素
just 操作符將某一個(gè)元素轉(zhuǎn)換為 Observable吝沫。
//一個(gè)序列只有唯一的元素 0:
let id = Observable.just(0)
//它相當(dāng)于:
let id = Observable<Int>.create { observer in
observer.onNext(0)
observer.onCompleted()
return Disposables.create()
}
- map
通過一個(gè)轉(zhuǎn)換函數(shù)呻澜,將 Observable 的每個(gè)元素轉(zhuǎn)換一遍
map 操作符將源 Observable 的每個(gè)元素應(yīng)用你提供的轉(zhuǎn)換方法,然后返回含有轉(zhuǎn)換結(jié)果的 Observable惨险。
let disposeBag = DisposeBag()
Observable.of(1, 2, 3)
.map { $0 * 10 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
輸出結(jié)果:
10
20
30
- merge
將多個(gè) Observables 合并成一個(gè)
通過使用 merge 操作符你可以將多個(gè) Observables 合并成一個(gè)羹幸,當(dāng)某一個(gè) Observable 發(fā)出一個(gè)元素時(shí),他就將這個(gè)元素發(fā)出辫愉。
如果栅受,某一個(gè) Observable 發(fā)出一個(gè) onError 事件,那么被合并的 Observable 也會將它發(fā)出恭朗,并且立即終止序列屏镊。
let disposeBag = DisposeBag()
let subject1 = PublishSubject<String>()
let subject2 = PublishSubject<String>()
Observable.of(subject1, subject2)
.merge()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext("A")
subject1.onNext("B")
subject2.onNext("1")
subject2.onNext("2")
subject1.onNext("AB")
subject2.onNext("3")
輸出結(jié)果:
A
B
1
2
AB
3