Observable 這個類是 Rx 框架的基礎(chǔ),可以稱它為可觀察序列。
它的作用,可以異步地產(chǎn)生一系列的 Event(事件),即一個 Observable 對象會隨著時間推移不定期地發(fā)出 event(element : T) 這樣一個東西。
而且這些 Event 還可以攜帶數(shù)據(jù),它的泛型就是用來指定這個 Event 攜帶的數(shù)據(jù)的類型。
有了可觀察序列,還需要有一個 Observer(訂閱者)來訂閱它,這樣訂閱者才能收到 Observable 發(fā)出的 Event
Event
public enum Event<Element> {
/// Next element is produced.
case next(Element)
/// Sequence terminated with an error.
case error(Swift.Error)
/// Sequence completed successfully.
case completed
}
可以看出 Event 就是個枚舉,也就是說一個 Observable 是可以發(fā)出 3 種不同類型的事件:
- next事件:就是那個可以攜帶數(shù)據(jù)的事件。
- error事件:表示一個錯誤,可以攜帶具體的錯誤內(nèi)容,一旦 Observable 發(fā)出了 error,則這個 Observable 就等于終止了,以后它再也不會發(fā)出 event 事件了。
- completed事件:表示 Observable 發(fā)出的事件正常結(jié)束了,跟 error 一樣,一旦發(fā)出了 completed,則這個 Observable 就等于終止了,以后它再也不會發(fā)出 event 事件了。
Observable的創(chuàng)建
- just() 方法
該方法通過傳入一個默認(rèn)值來初始化。指定了這個 Observable 所發(fā)出的事件攜帶的數(shù)據(jù)類型必須是 Int 類型的。
let observable = Observable<Int>.just(5)
- of() 方法
該方法可以接受可變數(shù)量的參數(shù)(必需要是同類型的)
let observable = Observable.of("A", "B", "C")
- from() 方法
該方法需要一個數(shù)組參數(shù)。下面樣例中數(shù)據(jù)的元素會被當(dāng)做這個 Observable 所發(fā)出 event 攜帶的數(shù)據(jù)內(nèi)容,最終效果同上面餓 of() 樣例是一樣的。
let observable = Observable.from(["A", "B", "C"])
- empty() 方法
該方法創(chuàng)建一個空內(nèi)容的 Observable 序列 - never() 方法
該方法創(chuàng)建一個永遠(yuǎn)不會發(fā)出 Event(也不會終止)的 Observable 序列
let observable = Observable<Int>.never()
- error() 方法
該方法創(chuàng)建一個不做任何操作,而是直接發(fā)送一個錯誤的 Observable 序列
enum MyError: Error {
case A
case B
}
let observable = Observable<Int>.error(MyError.A)
- create() 方法
該方法接受一個 block 形式的參數(shù),任務(wù)是對每一個過來的訂閱進(jìn)行處理
//這個block有一個回調(diào)參數(shù)observer就是訂閱這個Observable對象的訂閱者
//當(dāng)一個訂閱者訂閱這個Observable對象的時候,就會將訂閱者作為參數(shù)傳入這個block來執(zhí)行一些內(nèi)容
let observable = Observable<String>.create{observer in
//對訂閱者發(fā)出了.next事件,且攜帶了一個數(shù)據(jù)"hangge.com"
observer.onNext("hangge.com")
//對訂閱者發(fā)出了.completed事件
observer.onCompleted()
//在結(jié)尾 returen 一個Disposable 來取消訂閱
return Disposables.create()
}
//訂閱測試
observable.subscribe {
print($0)
}
8. deferred() 方法
該方法相當(dāng)于創(chuàng)建一個 Observable 工廠,通過傳入一個 block 來執(zhí)行延遲 Observable 序列創(chuàng)建的行為,而這個 block 里就是真正的實例化序列對象的地方
- interval() 方法
這個方法創(chuàng)建的 Observable 序列每隔一段設(shè)定的時間,會發(fā)出一個索引數(shù)的元素。而且它會一直發(fā)送下去。
let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable.subscribe { event in
print(event)
}
- timer() 方法
這個方法有兩種用法,一種是創(chuàng)建的 Observable 序列在經(jīng)過設(shè)定的一段時間后,產(chǎn)生唯一的一個元素
//5秒種后發(fā)出唯一的一個元素0
let observable = Observable<Int>.timer(5, scheduler: MainScheduler.instance)
observable.subscribe { event in
print(event)
}
另一種是創(chuàng)建的 Observable 序列在經(jīng)過設(shè)定的一段時間后,每隔一段時間產(chǎn)生一個元素
//延時5秒種后,每隔1秒鐘發(fā)出一個元素
let observable = Observable<Int>.timer(5, period: 1, scheduler: MainScheduler.instance)
observable.subscribe { event in
print(event)
}
Observable的訂閱、監(jiān)聽
有了 Observable,我們還要訂閱它,接收它發(fā)出的 Event
- 訂閱方式一
用 subscribe訂閱Observable 對象,該方法的 block 的回調(diào)參數(shù)就是被發(fā)出的 event 事件
let observable = Observable.of("A", "B", "C")
observable.subscribe { event in
print(event)
}
- 訂閱方式二
RxSwift 還提供了另一個 subscribe 方法,它可以把 event 進(jìn)行分類:
通過不同的 block 回調(diào)處理不同類型的 event。(其中 onDisposed 表示訂閱行為被 dispose 后的回調(diào))
同時會把 event 攜帶的數(shù)據(jù)直接解包出來作為參數(shù),方便我們使用。
let observable = Observable.of("A", "B", "C")
observable.subscribe(onNext: { element in
print(element)
}, onError: { error in
print(error)
}, onCompleted: {
print("completed")
}, onDisposed: {
print("disposed")
})
subscribe() 方法的 onNext、onError、onCompleted 和 onDisposed 這四個回調(diào) block 參數(shù)都是有默認(rèn)值的,即它們都是可選的。所以我們也可以只處理 onNext 而不管其他的情況。
let observable = Observable.of("A", "B", "C")
observable.subscribe(onNext: { element in
print(element)
})
事件監(jiān)聽
- doOn
用 doOn 方法來監(jiān)聽事件的生命周期,它會在每一次事件發(fā)送前被調(diào)用。
它和 subscribe 一樣,可以通過不同的 block 回調(diào)處理不同類型的 event。
如:do(onNext:) 方法就是在 subscribe(onNext:) 前調(diào)用
而 do(onCompleted:) 方法則會在 subscribe(onCompleted:) 前面調(diào)用
let observable = Observable.of("A", "B", "C")
observable
.do(onNext: { element in
print("Intercepted Next:", element)
}, onError: { error in
print("Intercepted Error:", error)
}, onCompleted: {
print("Intercepted Completed")
}, onDispose: {
print("Intercepted Disposed")
})
.subscribe(onNext: { element in
print(element)
}, onError: { error in
print(error)
}, onCompleted: {
print("completed")
}, onDisposed: {
print("disposed")
})
訂閱銷毀
Observable 從創(chuàng)建到終結(jié)流程
Observable 序列被創(chuàng)建出來后不會馬上就被激活發(fā)出 Event,而是要等到被訂閱了才會激活
而 Observable 序列激活后,要一直等到它發(fā)出了 .error 或 .completed 的 event 后,才被終結(jié)。dispose()
該方法可以手動取消一個訂閱行為。
如果訂閱結(jié)束了不再需要了,可以調(diào)用 dispose() 方法,把訂閱銷毀掉,防止內(nèi)存泄漏。
當(dāng)一個訂閱被 dispose 了,之后 observable 如果再發(fā)出 event,這個已經(jīng) dispose 的訂閱就收不到消息了
let observable = Observable.of("A", "B", "C")
//使用subscription常量存儲這個訂閱方法
let subscription = observable.subscribe { event in
print(event)
}
//調(diào)用這個訂閱的dispose()方法
subscription.dispose()
- DisposeBag
除dispose() 方法外,我們更經(jīng)常用到的是一個叫 DisposeBag 的對象來管理多個訂閱行為的銷毀
我們可以把DisposeBag 對象看成一個垃圾袋,把用過的訂閱行為都放進(jìn)去。
而這個 DisposeBag 會在自己快要 dealloc 時,對它里面的所有訂閱行為調(diào)用 dispose() 方法
let disposeBag = DisposeBag()
//第1個Observable,及其訂閱
let observable1 = Observable.of("A", "B", "C")
observable1.subscribe { event in
print(event)
}.disposed(by: disposeBag)
//第2個Observable,及其訂閱
let observable2 = Observable.of(1, 2, 3)
observable2.subscribe { event in
print(event)
}.disposed(by: disposeBag)
觀察者(Observer)
觀察者的作用就是監(jiān)聽事件,然后對事件做出響應(yīng)。或者說任何響應(yīng)事件的行為都是觀察者
如:
- 當(dāng)我們點擊按鈕,彈出一個提示框。那么這個“彈出一個提示框”就是觀察者
- 當(dāng)我們請求一個遠(yuǎn)程的 json 數(shù)據(jù)后,將其打印出來。那么這個“打印 json 數(shù)據(jù)”就是觀察者
1. 創(chuàng)建觀察者
- 創(chuàng)建觀察者最直接的方法是在 Observable 的 subscribe 、bind方法后面描述當(dāng)事件發(fā)生時,如何做出響應(yīng)
let observable = Observable.of("A", "B", "C")
observable.subscribe(onNext: { element in
print(element)
}, onError: { error in
print(error)
}, onCompleted: {
print("completed")
})
//Observable序列(每隔1秒鐘發(fā)出一個索引數(shù))
let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable
.map { "當(dāng)前索引數(shù):\($0 )"}
.bind { [weak self](text) in
//收到發(fā)出的索引數(shù)后顯示到label上
self?.label.text = text
}
.disposed(by: disposeBag)
- 使用 AnyObserver 創(chuàng)建觀察者
- AnyObserver 可以用來描敘任意一種觀察者,配合 subscribe 方法使用
//觀察者
let observer: AnyObserver<String> = AnyObserver { (event) in
switch event {
case .next(let data):
print(data)
case .error(let error):
print(error)
case .completed:
print("completed")
}
}
let observable = Observable.of("A", "B", "C")
observable.subscribe(observer)
- 配合 bindTo 方法使用
//觀察者
let observer: AnyObserver<String> = AnyObserver { [weak self] (event) in
switch event {
case .next(let text):
//收到發(fā)出的索引數(shù)后顯示到label上
self?.label.text = text
default:
break
}
}
//Observable序列(每隔1秒鐘發(fā)出一個索引數(shù))
let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable
.map { "當(dāng)前索引數(shù):\($0 )"}
.bind(to: observer)
.disposed(by: disposeBag)
}
- 使用 Binder 創(chuàng)建觀察者
相較于 AnyObserver 的大而全,Binder 更專注于特定的場景。
Binder 主要有以下兩個特征:
- 不會處理錯誤事件,確保綁定都是在給定 Scheduler 上執(zhí)行(默認(rèn) MainScheduler)
- 一旦產(chǎn)生錯誤事件,在調(diào)試環(huán)境下將執(zhí)行 fatalError,在發(fā)布環(huán)境下將打印錯誤信息。
Subjects
既是訂閱者,也是 Observable
說它是訂閱者,因為能夠動態(tài)地接收新的值
說它是Observable,是因為當(dāng) Subjects 有了新的值后,就會通過 Event 將新值發(fā)出給所有的訂閱者
一共有四種 Subjects,分別為:PublishSubject、BehaviorSubject、ReplaySubject、Variable
- PublishSubject
PublishSubject 是最普通的 Subject,它不需要初始值就能創(chuàng)建。
PublishSubject 的訂閱者從他們開始訂閱的時間點起,可以收到訂閱后 Subject 發(fā)出的新 Event,而不會收到他們在訂閱前已發(fā)出的 Event
let disposeBag = DisposeBag()
//創(chuàng)建一個PublishSubject
let subject = PublishSubject<String>()
//第1次訂閱subject
subject.subscribe(onNext: { string in
print("第1次訂閱:", string)
}, onCompleted:{
print("第1次訂閱:onCompleted")
}).disposed(by: disposeBag)
//由于當(dāng)前沒有任何訂閱者,所以這條信息不會輸出到控制臺
subject.onNext("111")
- BehaviorSubject
BehaviorSubject 需要通過一個默認(rèn)初始值來創(chuàng)建。
當(dāng)一個訂閱者來訂閱它的時候,這個訂閱者會立即收到 BehaviorSubjects 上一個發(fā)出的 event。之后就跟正常的情況一樣,它也會接收到 BehaviorSubject 之后發(fā)出的新的 event
let disposeBag = DisposeBag()
//創(chuàng)建一個BehaviorSubject
let subject = BehaviorSubject(value: "111")
//第1次訂閱subject
subject.subscribe { event in
print("第1次訂閱:", event)
}.disposed(by: disposeBag)
變換操作符
- map
該操作符通過傳入一個函數(shù)閉包把原來的 Observable 序列轉(zhuǎn)變?yōu)橐粋€新的 Observable 序列
變換操作指的是對原始的 Observable 序列進(jìn)行一些轉(zhuǎn)換
let disposeBag = DisposeBag()
Observable.of(1, 2, 3)
.map { $0 * 10}
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
- flatMap
map 在做轉(zhuǎn)換的時候容易出現(xiàn)“升維”的情況。即轉(zhuǎn)變之后,從一個序列變成了一個序列的序列。
而 flatMap 操作符會對源 Observable 的每一個元素應(yīng)用一個轉(zhuǎn)換方法,將他們轉(zhuǎn)換成 Observables。 然后將這些 Observables 的元素合并之后再發(fā)送出來。即又將其 “拍扁”(降維)成一個 Observable 序列。
這個操作符是非常有用的。比如當(dāng) Observable 的元素本生擁有其他的 Observable 時,我們可以將所有子 Observables 的元素發(fā)送出來