目錄
一、RxSwift是什么,為什么要使用RxSwift
二、RxSwift的核心角色
?1、Event
?2、Observable
?3、Observer要做的處理
?4、Observer
三、Observer監(jiān)聽Observable,以及監(jiān)聽行為的釋放
?1、Observer監(jiān)聽Observable
?2、監(jiān)聽行為的釋放
四、Subjects
一、RxSwift是什么,為什么要使用RxSwift
RxSwift是響應(yīng)式編程的一個開源框架,所謂響應(yīng)式編程(Reactive Programming,簡稱RP)就是一種編程范式——即怎么寫代碼的方法論。
1??如果項目里你用的是MVVM架構(gòu)的話,響應(yīng)式編程則提供了更加簡單優(yōu)雅的方式來做ViewModel和View的雙向綁定,從而使得你的MVVM更加如虎添翼;2??傳統(tǒng)方式中我們經(jīng)常使用代理、block、通知等方式來進行事件傳遞,它們各有各的寫法,而響應(yīng)式編程則可以讓事件傳遞的方式做到統(tǒng)一——鏈式調(diào)用,同時能降低代碼的耦合度提高代碼內(nèi)聚度(事件里通常會攜帶數(shù)據(jù),所以可以直接把事件看成是數(shù)據(jù)、把事件傳遞看成是數(shù)據(jù)傳遞),當然響應(yīng)式編程還有很多其它方面的用途你可以去挖掘,比如在網(wǎng)絡(luò)請求方面的應(yīng)用、在手勢方面的應(yīng)用、在多個異步任務(wù)處理方面的應(yīng)用等。
比較出名和成熟的響應(yīng)式編程框架有:
- ReactiveCocoa,簡稱RAC,有OC和Swift版本
- ReactiveX,簡稱Rx,有眾多編程語言的版本,如RxJava、RxKotlin、RxSwift、RxDart等,它們的API基本都是一樣的,只不過是基于不同語言實現(xiàn)的而已,但是沒有OC版本,不過如果真得要用OC開發(fā),我們也可以O(shè)C和Swift混編來調(diào)用RxSwift
Rx有這么多編程語言的版本,足以說明大家都比較認可它的那一套機制,社區(qū)肯定要比RAC活躍得多,因此如果要選擇一個響應(yīng)式編程框架,推薦Rx。
項目里要想使用RxSwift,得先安裝RxSwift和RxCocoa這兩個框架,這里只演示使用CocoaPods的安裝方式,像使用其它三方庫一樣直接在Podfile文件里依賴這兩個框架,執(zhí)行pod install即可。
pod 'RxSwift', '~> 5.0'
pod 'RxCocoa', '~> 5.0'
然后在想使用RxSwift的地方導(dǎo)入這兩個框架。
// RxSwift是Rx標準API的Swift版本實現(xiàn),不包含任何iOS相關(guān)的內(nèi)容
import RxSwift
// RxCocoa則是基于RxSwift給iOS的UI控件擴展了很多Rx特性
import RxCocoa
二、RxSwift的核心角色
iOS開發(fā)中的KVO、通知都是觀察者設(shè)計模式,在設(shè)計模式中它可是一種重中之重的設(shè)計模式。比如寶寶在睡覺,爸爸媽媽總不能一直在旁邊看著吧,那樣就太累了,他們該做啥事做啥事,只要聽到寶寶的哭聲,給寶寶喂奶就行了,這就是一個典型的觀察者設(shè)計模式。在這個例子里,寶寶是被觀察者,爸爸媽媽是觀察者,只要被觀察者發(fā)出了事件——哭聲,觀察者收到后就會做出相應(yīng)的處理——喂奶。據(jù)此我們可以得到觀察者設(shè)計模式的核心角色:
- 被觀察者(也叫發(fā)布者)
- 被觀察者要發(fā)出的事件
- 觀察者(也叫訂閱者)
- 觀察者要做的處理
RxSwift跟觀察者設(shè)計模式很像,核心角色也是上面這四個。
1、Event
Event就是這么一個泛型枚舉:
public enum Event<Element> {
case next(Element)
case error(Swift.Error)
case completed
}
這個泛型枚舉一共有三個值,所以事件一共有三種類型,也就是說Observable只可能發(fā)出這三種類型的事件:
- next事件:一個攜帶正常數(shù)據(jù)的正常事件,正常數(shù)據(jù)的數(shù)據(jù)類型就是這個泛型Element、它可以是任意類型、不過早在Observable那兒就指定好了,正常數(shù)據(jù)會被掛在事件的element屬性上
- error事件:一個攜帶錯誤信息的錯誤事件,錯誤信息的數(shù)據(jù)類型為Error類型,錯誤信息會被掛在事件的error屬性上
// Error其實是一個協(xié)議,要想發(fā)出error事件,我們就得自定義Error
enum CustomError: Error {
case error1
case error2
case error3
}
- completed事件:一個什么數(shù)據(jù)都不攜帶的完成事件
Event就是事件,它就是Observable隨著時間的推移源源不斷發(fā)出的東西。事件的作用就是作為數(shù)據(jù)的載體來攜帶數(shù)據(jù),next事件就是正常數(shù)據(jù)的載體,error事件就是錯誤信息的載體,也就是說Observable要想發(fā)送一個正常數(shù)據(jù)就發(fā)出一個next事件,Observable要想發(fā)送一個錯誤信息就發(fā)出一個error事件,需要注意的是Observable一旦發(fā)出error事件就代表它因錯誤而終止了,以后再也不會發(fā)出事件。completed事件雖然不是數(shù)據(jù)的載體,但它也是一個不可或缺的事件,Observable一旦發(fā)出completed事件就代表它正常終止了,以后再也不會發(fā)出事件。
2、Observable
Observable就是這么一個泛型類:
// 注意:類型為ObservableType
public class Observable<Element> : ObservableType {
...
}
Observable就是被觀察者,它其實是一個事件序列(Event Sequence),所以我們通常又稱它為被觀察序列。Observable的作用就是隨著時間的推移源源不斷地發(fā)出事件,你想它發(fā)出的事件掛什么數(shù)據(jù)類型的數(shù)據(jù)就把它的泛型Element搞成什么數(shù)據(jù)類型就行了。
- 創(chuàng)建Observable及Observable發(fā)出事件
// 1、怎么創(chuàng)建一個observable?
//
// 調(diào)用Observable的類方法create就可以創(chuàng)建一個observable,假設(shè)這個observable發(fā)出的事件掛的數(shù)據(jù)為Int類型
//
// create方法的入?yún)⑹且粋€閉包,這個閉包的入?yún)⑹且粋€observer——這個observer就是將來監(jiān)聽該observable的observer,這個閉包的返回值是一個disposable
// create方法的返回值是一個observable
let observable = Observable<Int>.create { observer in
// 2、observable怎么發(fā)出事件?
//
// 這個閉包屬于observable,所以在這個環(huán)境里:
// observable給observer發(fā)出next事件,換句話說就是給observer發(fā)送一個next消息(消息機制),即讓observer調(diào)用一下它的onNext方法
// observable給observer發(fā)出completed事件或error事件,同理
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onCompleted()
// observer.onError(CustomError.error1)
// 因為observable一旦發(fā)出completed事件或error事件就終止了,所以后面這三個事件是發(fā)不出去的
observer.onNext(4)
observer.onNext(5)
observer.onNext(6)
return Disposables.create()
}
- 快捷創(chuàng)建Observable及Observable發(fā)出事件
// 單個事件Observable:該Observable只能發(fā)出一個next事件 + 一個completed事件
//
// 1、調(diào)用Observable的類方法just就可以快捷創(chuàng)建一個單個事件observable,可以省略泛型,直接傳你想發(fā)送的數(shù)據(jù)就行,會自動給你泛好
// 2、創(chuàng)建好、被監(jiān)聽后,該Observable就會自動發(fā)出事件
let justObservable = Observable.just(1)
// 等價于
let observable = Observable<Int>.create { observer in
observer.onNext(1)
observer.onCompleted()
return Disposables.create()
}
// 多個事件Observable:該Observable能發(fā)出多個next事件 + 一個completed事件
//
// 1、調(diào)用Observable的類方法from或of就可以快捷創(chuàng)建一個多個事件observable,可以省略泛型,直接傳你想發(fā)送的數(shù)據(jù)就行,會自動給你泛好
// 2、創(chuàng)建好、被監(jiān)聽后,該Observable就會自動發(fā)出事件
let fromObservable = Observable.from([1, 2, 3]) // 通過數(shù)組來生成多個next事件
let ofObservable = Observable.of(1, 2, 3) // 通過可變參數(shù)來生成多個next事件
// 等價于
let observable = Observable<Int>.create { observer in
observer.onNext(1)
observer.onNext(2)
observer.onNext(3)
observer.onCompleted()
return Disposables.create()
}
// 重復(fù)N次Observable:給定一個重復(fù)次數(shù)N,該Observable就會重復(fù)發(fā)出同一個next事件N次 + 一個completed事件
let repeatElementObservable = Observable.repeatElement(1)
repeatElementObservable.take(5)
// 定時器Observable:完全就是一個定時器,必須泛整型。延遲多長時間、每隔多長時間、在哪個線程,該Observable會像個定時器一樣不斷發(fā)出累加的整數(shù)
//
// 如果想取消定時器,其實不用取消定時器Observable,你只需要把監(jiān)聽行為給釋放掉就可以了,這樣的話定時器Observable還是存在的,它并不會發(fā)出completed事件或error事件
let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
3、Observer要做的處理
這個沒什么好說的,通常就是一個閉包。
4、Observer
Observer有兩種類型:AnyObserver(隨便什么東西都能充當AnyObserver這種類型的觀察者)和Binder(一般都是一些UI控件的屬性在充當Binder這種類型的觀察者),但它們都是一個泛型結(jié)構(gòu)體:
// 注意:類型為ObserverType
public struct AnyObserver<Element> : ObserverType {
...
}
// 注意:類型為ObserverType
public struct Binder<Element>: ObserverType {
...
}
Observer就是觀察者。Observer的作用就是監(jiān)聽Observable(至于怎么監(jiān)聽,會在下一小節(jié)說),并在收到Observable發(fā)出的事件時做出相應(yīng)的處理,需要注意的是Observer想要監(jiān)聽的數(shù)據(jù)的數(shù)據(jù)類型就是泛型的這個Element,如果它跟Observable和Event那里的泛型Element不一樣,我們就得先通過map等函數(shù)把數(shù)據(jù)類型給搞一樣。
- 創(chuàng)建一個AnyObserver及AnyObserver做相應(yīng)的處理
// 1、怎么創(chuàng)建一個anyObeserver?
//
// 調(diào)用AnyObserver的init方法就可以創(chuàng)建一個anyObserver,假設(shè)這個anyObserver想要監(jiān)聽的數(shù)據(jù)的數(shù)據(jù)類型為Int
//
// init方法的入?yún)⑹且粋€閉包,這個閉包的入?yún)⑹且粋€event——這個event就是將來被觀察的Observable所發(fā)出的事件,這個閉包的執(zhí)行體就是AnyObserver要做的處理
let anyObserver = AnyObserver<Int>.init { event in
// 2、anyObserver怎么做出相應(yīng)的處理?
// 在這個閉包的執(zhí)行體里做相應(yīng)的處理即可
switch event {
case .next:
print("next:\(event.element)")
case .error:
print("error:\(event.error)")
case .completed:
print("completed")
}
}
- 創(chuàng)建一個Binder及Binder做相應(yīng)的處理
// 1、怎么創(chuàng)建一個Binder?
//
// 調(diào)用Binder的init方法就可以創(chuàng)建一個binder,假設(shè)這個binder想要監(jiān)聽的數(shù)據(jù)的數(shù)據(jù)類型為String(假設(shè)我們想監(jiān)聽字符串數(shù)據(jù),把監(jiān)聽到的字符串數(shù)據(jù)設(shè)置到一個label上顯示)
//
// init方法的第一個入?yún)⑹侵改阋驯O(jiān)聽到的數(shù)據(jù)設(shè)置給誰來使用,通常是一個UI控件
// init方法的第二個入?yún)⑹且粋€閉包,這個閉包的第一個入?yún)⒕褪乔懊娴哪莻€UI控件,第二個入?yún)⒕褪潜O(jiān)聽到的字符串數(shù)據(jù),這個閉包的執(zhí)行體就是binder要做的處理
let binder = Binder<String>.init(label) { label, element in
// 2、binder怎么做出相應(yīng)的處理?
// 在這個閉包的執(zhí)行體里做相應(yīng)的處理即可
label.text = element
}
三、Observer監(jiān)聽Observable,以及監(jiān)聽行為的釋放
1、Observer監(jiān)聽Observable
現(xiàn)在我們已經(jīng)成功擁有了四大核心角色,被觀察者 + 被觀察者要發(fā)出的事件、觀察者 + 觀察者要做的處理,那這兩大陣營怎么聯(lián)系起來呢,也就是說觀察者怎么才能收到被觀察者發(fā)出的事件、進而觸發(fā)相應(yīng)的處理呢?很簡單,就是Observer監(jiān)聽Observable。
- AnyObserver監(jiān)聽Observable
let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
let anyObserver = AnyObserver<Int>.init { event in
switch event {
case .next:
print("next:\(event.element)") // 會打印:0、1、2、3、...
case .error:
print("error:\(event.error)")
case .completed:
print("completed")
}
}
// anyObserver監(jiān)聽timerObservable,就這么簡單
timerObservable.subscribe(anyObserver)
- Binder監(jiān)聽Observable
// 界面上搞一個label
@IBOutlet weak var label: UILabel!
let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
let binder = Binder<String>.init(label) { label, element in
label.text = element
}
// binder監(jiān)聽timerObservable
// 但是timerObservable發(fā)出的事件掛的數(shù)據(jù)是Int類型
// 而binder監(jiān)聽的確實String類型
// 所以得把timerObservable發(fā)出的事件掛的Int數(shù)據(jù)通過map函數(shù)轉(zhuǎn)換成String數(shù)據(jù)
// 就這么簡單
timerObservable
.map { element in
return "數(shù)字是:\(element)"
}
.subscribe(binder)
// Binder還有一個專門的bindTo方法用來監(jiān)聽Observable,不過跟subscribe方法是等價的
timerObservable
.map { element in
return "數(shù)字是:\(element)"
}
.bind(to: binder)
- 當然除了AnyObserver和Binder這種標標準準的Observer可以監(jiān)聽Observable之外,我們還可以直接用一個閉包來監(jiān)聽Observable,這種情況下這個閉包其實也是一個廣義上的觀察者,而且這個觀察者是把原來標標準準的觀察者和觀察者要做的處理兩個角色融為一體了
let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
// 方式1
timerObservable
.subscribe { event in
switch event {
case .next:
print("next:\(event.element)") // 會打印:0、1、2、3、...
case .error:
print("error:\(event.error)")
case .completed:
print("completed")
}
}
// 方式2
timerObservable
.subscribe(onNext: { element in
print("next:\(element)") // 會打印:0、1、2、3、...
}, onError: { error in
print("error:\(error)")
}, onCompleted: {
print("completed")
})
因此將來我們看到subscribe方法或bindTo方法前面的東西肯定就是個Observable,后面的東西肯定就是個廣義的Observer——標標準準的Observer + 閉包。
2、監(jiān)聽行為的釋放
其實每當Observer監(jiān)聽Observable時就產(chǎn)生了一個監(jiān)聽行為——即subscribe方法或bindTo方法會返回一個Disposable類型的實例,一定要記得在適當?shù)臅r機釋放這個監(jiān)聽行為,以免內(nèi)存泄漏,注意當這個監(jiān)聽行為被釋放后,僅僅是切斷了兩大陣營之間的聯(lián)系,Observable和Observer這些對象本身是沒被銷毀的。釋放的方式有三種:
- 立即釋放監(jiān)聽行為(實際開發(fā)中使用較少)
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
let anyObserver = AnyObserver<Int>.init { event in
switch event {
case .next:
print("next:\(event.element)")
case .error:
print("error:\(event.error)")
case .completed:
print("completed")
}
}
let disposable = timerObservable.subscribe(anyObserver)
// 立即釋放監(jiān)聽行為——即接收完釋放之前的一波數(shù)據(jù)后立即釋放,類似于release
disposable.dispose()
}
}
- 自動釋放監(jiān)聽行為(實際開發(fā)中使用較多)
class ViewController: UIViewController {
// 類似于autoreleasepool
//
// 它會把所有的監(jiān)聽行為都放進去,等到它即將銷毀時再對它里面所有的監(jiān)聽行為都調(diào)用一次dispose方法
// 現(xiàn)在bag屬性的生命周期是跟當前viewController一樣的
let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
let anyObserver = AnyObserver<Int>.init { event in
switch event {
case .next:
print("next:\(event.element)")
case .error:
print("error:\(event.error)")
case .completed:
print("completed")
}
}
timerObservable.subscribe(anyObserver).disposed(by: bag)
}
}
- 手動釋放監(jiān)聽行為
class ViewController: UIViewController {
// 定義一個屬性
var disposable: Disposable?
override func viewDidLoad() {
super.viewDidLoad()
let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
let anyObserver = AnyObserver<Int>.init { event in
switch event {
case .next:
print("next:\(event.element)")
case .error:
print("error:\(event.error)")
case .completed:
print("completed")
}
}
// 把監(jiān)聽行為記錄下來
disposable = timerObservable.subscribe(anyObserver)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// 在合適的時機手動釋放監(jiān)聽行為
disposable?.dispose()
}
}
四、Subjects
Subjects同時充當了Observable和Observer的角色,也就是說它既是一個被觀察者、也是一個觀察者,它既能發(fā)出事件、也能做相應(yīng)的處理。常用的Subjects有四種:
- PublishSubject
class ViewController: UIViewController {
let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let publishSubject = PublishSubject<Int>.init()
// 這里publishSubject在充當Observer的角色,幫Observable發(fā)出事件
// 還記得之前創(chuàng)建Observable時,Observable是怎么發(fā)出事件的嗎?就是給Observer發(fā)送onNext消息發(fā)出的,onNext本來就是Observer的方法,所以這里就體現(xiàn)了publishSubject在充當Observer的角色
publishSubject.onNext(1)
publishSubject.onNext(2)
publishSubject.onNext(3)
// 這里publishSubject在充當Observable的角色,只會向觀察者發(fā)送觀察者監(jiān)聽它之后的事件,不會向觀察者發(fā)送觀察者監(jiān)聽它之前的事件
publishSubject.subscribe { event in
print(event) // 4、5、6
}.disposed(by: bag)
publishSubject.onNext(4)
publishSubject.onNext(5)
publishSubject.onNext(6)
}
}
- BehaviorSubject
class ViewController: UIViewController {
let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let behaviorSubject = BehaviorSubject<Int>(value: 1)
// 這里behaviorSubject在充當Observer的角色,幫Observable發(fā)出事件
behaviorSubject.onNext(2)
behaviorSubject.onNext(3)
// 這里behaviorSubject在充當Observable的角色,會向觀察者發(fā)送觀察者監(jiān)聽它之前的最后一個事件 + 觀察者監(jiān)聽它之后的事件
behaviorSubject.subscribe { event in
print(event) // 3、4、5、6
}.disposed(by: bag)
behaviorSubject.onNext(4)
behaviorSubject.onNext(5)
behaviorSubject.onNext(6)
}
}
- ReplaySubject
class ViewController: UIViewController {
let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let replaySubject = ReplaySubject<Int>.create(bufferSize: 2) // 假設(shè)要緩存兩個事件
// 這里replaySubject在充當Observer的角色,幫Observable發(fā)出事件
replaySubject.onNext(1)
replaySubject.onNext(2)
replaySubject.onNext(3)
// 這里replaySubject在充當Observable的角色,會向觀察者發(fā)送觀察者監(jiān)聽它之前緩存的N個事件 + 觀察者監(jiān)聽它之后的事件
replaySubject.subscribe { event in
print(event) // 2、3、4、5、6。緩存的是最后兩個事件,因為是序列,所以會按順序把事件發(fā)出來
}.disposed(by: bag)
replaySubject.onNext(4)
replaySubject.onNext(5)
replaySubject.onNext(6)
}
}
- BehaviorRelay(Variable已經(jīng)被廢棄了,用BehaviorRelay代替,它倆其實都是對BehaviorSubject的封裝,功能一樣)
class ViewController: UIViewController {
let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let behaviorRelay = BehaviorRelay<Int>.init(value: 1)
// 這里behaviorRelay在充當Observer的角色,幫Observable發(fā)出事件
behaviorRelay.accept(2)
behaviorRelay.accept(3)
// 這里behaviorRelay在充當Observable的角色,會向觀察者發(fā)送觀察者監(jiān)聽它之前的最后一個事件 + 觀察者監(jiān)聽它之后的事件
behaviorRelay.subscribe { event in
print(event) // 3、4、5、6
}.disposed(by: bag)
behaviorRelay.accept(4)
behaviorRelay.accept(5)
behaviorRelay.accept(6)
}
}
參考
1、RxSwift中文文檔
2、RxSwift大全