簡(jiǎn)介
它拓展了觀察者模式。使你能夠自由組合多個(gè)異步事件畜晰,而不需要去關(guān)心線程,同步瑞筐,線程安全舷蟀,并發(fā)數(shù)據(jù)以及I/O阻塞。
函數(shù)響應(yīng)式編程
- 函數(shù)式編程:是種編程范式面哼,它需要我們將函數(shù)作為參數(shù)傳遞,或者作為返回值返還扫步。我們可以通過(guò)組合不同的函數(shù)來(lái)得到想要的結(jié)果魔策。
- 響應(yīng)式編程: a=b+c表示將表達(dá)式的結(jié)果賦給 a,而之后改變 b 或 c的值不會(huì)影響 a河胎。但在響應(yīng)式編程中闯袒,a的值會(huì)隨著 b或 c的更新而更新。a=b+c聲明的是一種綁定關(guān)系游岳。
RxSwift優(yōu)點(diǎn)
- 在業(yè)務(wù)層面實(shí)現(xiàn)代碼邏輯分離政敢,方便后期維護(hù)和拓展
- 極大提高程序響應(yīng)速度,充分發(fā)掘CPU的能力
- 幫助開(kāi)發(fā)者提高代碼的抽象能力和充分理解業(yè)務(wù)邏輯
- Rx豐富的操作符會(huì)幫助我們極大的簡(jiǎn)化代碼邏輯
核心
- Observable - 可被監(jiān)聽(tīng)的序列產(chǎn)列
- Observer - 觀察者
- Operator - 操作符
- Disposable - 管理綁定(訂閱)的生命周期
- Schedulers - 調(diào)度器(線程隊(duì)列調(diào)配)
Observable - 可被監(jiān)聽(tīng)的序列
框架已經(jīng)幫我們創(chuàng)建好了許多常用的序列胚迫。例如:button的點(diǎn)擊喷户,textField的當(dāng)前文本,switch的開(kāi)關(guān)狀態(tài)访锻,slider的當(dāng)前數(shù)值等等褪尝。
let numbers: Observable<Int> = Observable.create { observer -> Disposable 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()
}
Observer - 觀察者
觀察者最直接的方法就是在 Observable 的 subscribe 方法后面描述,事件發(fā)生時(shí)期犬,需要如何做出響應(yīng)河哑。而觀察者就是由后面的 onNext,onError龟虎,onCompleted的這些閉包構(gòu)建出來(lái)的璃谨。
- observer.onNext(0) 就代表產(chǎn)生了一個(gè)元素,他的值是 0鲤妥。
- onCompleted()結(jié)束
- onError()發(fā)生錯(cuò)誤
tap.subscribe(onNext: { [weak self] in
self?.showAlert()
}, onError: { error in
print("發(fā)生錯(cuò)誤: \(error.localizedDescription)")
}, onCompleted: {
print("任務(wù)完成")
})
操作符
- filter - 過(guò)濾
// 溫度
let rxTemperature: Observable<Double> = ...
// filter 操作符
rxTemperature.filter { temperature in temperature > 33 }
.subscribe(onNext: { temperature in
print("高溫:\(temperature)度")
})
.disposed(by: disposeBag)
- map - 轉(zhuǎn)換
let disposeBag = DisposeBag()
Observable.of(1, 2, 3)
.map { $0 * 10 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
- zip - 配對(duì)
let disposeBag = DisposeBag()
let first = PublishSubject<String>()
let second = PublishSubject<String>()
Observable.zip(first, second) { $0 + $1 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
first.onNext("1")
second.onNext("A")
1A
Disposable - 可被清除的資源
通常來(lái)說(shuō)佳吞,一個(gè)序列如果發(fā)出了 error 或者 completed 事件,那么所有內(nèi)部資源都會(huì)被釋放旭斥。如果你需要提前釋放這些資源或取消訂閱的話容达,那么你可以對(duì)返回的 可被清除的資源(Disposable) 調(diào)用 dispose 方發(fā)
通常情況下,我們不需要手動(dòng)調(diào)用 dispose 方法的
使用 清除包(DisposeBag) 或者 takeUntil 操作符 來(lái)管理訂閱的生命周期
- DisposeBag - 清除包
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()
}
- takeUntil
使得訂閱一直持續(xù)到控制器的 dealloc 事件產(chǎ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)
_ = doSomethingOutlet.rx.tap
.takeUntil(self.rx.deallocated)
.subscribe(onNext: { [weak self] in self?.showAlert() })
}
Schedulers - 調(diào)度器
Schedulers 是 Rx 實(shí)現(xiàn)多線程的核心模塊垂券,它主要用于控制任務(wù)在哪個(gè)線程或隊(duì)列運(yùn)行花盐。
GCD:
// 后臺(tái)取得數(shù)據(jù)羡滑,主線程處理結(jié)果
DispatchQueue.global(qos: .userInitiated).async {
let data = try? Data(contentsOf: url)
DispatchQueue.main.async {
self.data = data
}
}
RxSwift:
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 來(lái)決定數(shù)據(jù)序列的構(gòu)建函數(shù)在哪個(gè) Scheduler 上運(yùn)行。以上例子中算芯,由于獲取 Data 需要花很長(zhǎng)的時(shí)間柒昏,所以用 subscribeOn 切換到 后臺(tái) Scheduler 來(lái)獲取 Data。這樣可以避免主線程被阻塞熙揍。
observeOn 來(lái)決定在哪個(gè) Scheduler 監(jiān)聽(tīng)這個(gè)數(shù)據(jù)序列职祷。以上例子中,通過(guò)使用 observeOn 方法切換到主線程來(lái)監(jiān)聽(tīng)并且處理結(jié)果届囚。
MainScheduler 主線程
SerialDispatchQueueScheduler
抽象了串行 DispatchQueue有梆。如果你需要執(zhí)行一些串行任務(wù),可以切換到這個(gè) Scheduler 運(yùn)行意系。ConcurrentDispatchQueueScheduler
抽象了并行 DispatchQueue泥耀。如果你需要執(zhí)行一些并發(fā)任務(wù),可以切換到這個(gè) Scheduler 運(yùn)行蛔添。OperationQueueScheduler 抽象了 NSOperationQueue痰催。它具備 NSOperationQueue 的一些特點(diǎn),例如迎瞧,你可以通過(guò)設(shè)置 maxConcurrentOperationCount夸溶,來(lái)控制同時(shí)執(zhí)行并發(fā)任務(wù)的最大數(shù)量。
Error Handling - 錯(cuò)誤處理
RxSwift 主要有兩種錯(cuò)誤處理機(jī)制:
- retry - 重試
- catch - 恢復(fù)
retry - 重試
- retry
let rxJson: Observable<JSON> = ...
rxJson
.retry(3)
.subscribe(onNext: { json in
print("取得 JSON 成功: \(json)")
}, onError: { error in
print("取得 JSON 失敗: \(error)")
})
.disposed(by: disposeBag)
失敗后重試三次
- retryWhen
操作符凶硅,這個(gè)操作符主要描述應(yīng)該在何時(shí)重試缝裁,并且通過(guò)閉包里面返回的 Observable 來(lái)控制重試的時(shí)機(jī):
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)
catchError - 恢復(fù)
- catchError
可以在錯(cuò)誤產(chǎn)生時(shí),用一個(gè)備用元素或者一組備用元素將錯(cuò)誤替換掉:
let rxData: Observable<Data> = ... // 網(wǎng)絡(luò)請(qǐng)求的數(shù)據(jù)
let cahcedData: Observable<Data> = ... // 之前本地緩存的數(shù)據(jù)
rxData
.catchError { _ in cahcedData }
.subscribe(onNext: { date in
print("獲取數(shù)據(jù)成功: \(date.count)")
})
.disposed(by: disposeBag)
- catchErrorJustReturn 當(dāng)錯(cuò)誤產(chǎn)生時(shí)足绅,就返回一個(gè)空數(shù)組压语,于是就會(huì)顯示一個(gè)空列表頁(yè)。
Result
展示錯(cuò)誤結(jié)果
updateUserInfoButton.rx.tap
.withLatestFrom(rxUserInfo)
.flatMapLatest { userInfo -> Observable<Result<Void>> in
return update(userInfo)
.map(Result.success) // 轉(zhuǎn)換成 Result
.catchError { error in Observable.just(Result.failure(error)) }
}
.observeOn(MainScheduler.instance)
.subscribe(onNext: { result in
switch result { // 處理 Result
case .success:
print("用戶信息更新成功")
case .failure(let error):
print("用戶信息更新失敱嗉臁: \(error.localizedDescription)")
}
})
.disposed(by: disposeBag)
其他
后面會(huì)講下具體實(shí)踐-UI上的使用胎食,還有更多理論性的東西就看文檔就ok了,操作符遇到了再查允懂。
基本常用控件
UITablView和UICollectionview使用
其他不常用控件
所有例子demo