RxSwift入坑解讀-你所需要知道的各種概念

作者:沸沸騰

原文鏈接:RxSwift入坑解讀-你所需要知道的各種概念

相信大家很早就聽說過函數式響應編程概念,我是去年面試的時候接觸到函數式響應編程的,當時也是第一次接觸到MVVM這個概念,轉眼都一年過去了,我卻沒有在函數式編程上做深入的研究,說來還真是慚愧。

不過最近由於想要使用RxSwift,所以趁這個時候好好接觸和研究一下傳說中的函數式編程,由於網上關於RxSwift的教程資料很少,這篇文章其實就是最RxSwift官方文檔和一些概念做一些解讀。算是大家學習的參考文章吧! 先挖個坑,這可能會是一個RxSwift系列,希望大家在學習的時候有所參考。

RxSwift是什麼

RxSwif是ReactiveX的Swift版本,也就是一個函數式響應編程的框架。對,就這一句話。想要知道他做什麼的,我們先來了解一下觀察者模式。

觀察者模式

關於觀察者模式我想大夥應該都很了解了吧,什麼KVO,通知等都是觀察者模式,在設計模式中他可是一個重中之重的設計模式啊!比如一個寶寶在睡覺,爸爸媽媽,爺爺奶奶總不能在那邊一隻看著吧?那樣子太累了。他們該做啥事就做啥事唄,只要聽到寶寶的哭聲,他們就給寶寶餵奶就行了。這就是一個典型的觀察者模式。寶寶是被觀察者,爸爸媽媽等是觀察者也稱作訂閱者,只要被觀察者發出了某些事件比如寶寶哭聲、叫聲都是一個事件,通知到訂閱者,訂閱者們就可以做相應的處理工作。哈哈,觀察者模式很簡單吧?

RxSwift做了什麼

RxSwift把我們程序中每一個操作都看成一個事件,比如一個TextField中的文本改變,一個按鈕被點擊,或者一個網路請求結束等,每一個事件源就可以看成一個管道,也就是sequence,比如TextField,當我們改變裡面的文本的時候,這個TextField就會不斷的發出事件,從他的這個sequence中不斷的流出,我們只需要監聽這個sequence,每流出一個事件就做相應的處理。同理,Button也是一個sequence,每點擊一次就流出一個事件。也就是我們把每一步都想成是一個事件就好去理解RxSwift了。看下圖是不是很好理解了?

Observable和Observer

理解了觀察者模式這兩個概念就很好理解了,Observable就是可被觀察的,也就是我們說的寶寶,他也是事件源。而Observer就是我們的觀察者,也就是當收到事件的時候去做某些處理的爸爸媽媽。觀察者需要去訂閱(subscribe)被觀察者,才能收到Observable的事件通知消息。

下面開始一些基本概念解讀,通讀一遍你會對RxSwift有非常深刻的認識了,其實也就是對整理了一下官方文檔和加上自己的一些理解

創建和訂閱被觀察者

下面創建被觀察者其實就是創建一個Obserable的sequence,就是創建一個流,然後就可以被訂閱subscribe,這樣被觀察者發出時間消失,我們就能做相應的處理

DisposeBag

DisposeBag其實就相當於iOS中的ARC似得,會在適當的時候銷毀觀察者,相當於內存管理者吧。

subscribe

subscribe是訂閱sequence發出的事件,比如next事件,error事件等。而subscribe(onNext:)是監聽sequence發出的next事件中的element進行處理,他會忽略error和completed事件。相對應的還有subscribe(onError:) 和 subscribe(onCompleted:)

never

never就是創建一個sequence,但是不發出任何事件信號。

let disposeBag = DisposeBag()nlet neverSequence = Observable<String>.never()nnlet neverSequenceSubscription = neverSequencen .subscribe { _ inn print("This will never be printed")n}.addDisposableTo(disposeBag)n

結果是什麼都不列印n

empty

empty就是創建一個空的sequence,只能發出一個completed事件

let disposeBag = DisposeBag()nn Observable<Int>.empty()n .subscribe { event inn print(event)n }n .addDisposableTo(disposeBag)n

completedn

just

just是創建一個sequence只能發出一種特定的事件,能正常結束

let disposeBag = DisposeBag()nnObservable.just("??")n .subscribe { event inn print(event)n }n .addDisposableTo(disposeBag)n

next(??)ncompletedn

of

of是創建一個sequence能發出很多種事件信號

let disposeBag = DisposeBag()nnObservable.of("??", "??", "??", "??")n .subscribe(onNext: { element inn print(element)n })n .addDisposableTo(disposeBag)n

??n??n??n??n

如果把上面的onNext:去掉的話,結果會是這樣子,也正好對應了我們subscribe中,subscribe只監聽事件。

next(??)nnext(??)nnext(??)nnext(??)ncompletedn

from

from就是從集合中創建sequence,例如數組,字典或者Set

let disposeBag = DisposeBag()nnObservable.from(["??", "??", "??", "??"])n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

create

我們也可以自定義可觀察的sequence,那就是使用create

create操作符傳入一個觀察者observer,然後調用observer的onNext,onCompleted和onError方法。返回一個可觀察的obserable序列。

let disposeBag = DisposeBag()nnlet myJust = { (element: String) -> Observable<String> inn return Observable.create { observer inn observer.on(.next(element))n observer.on(.completed)n return Disposables.create()n }n}nnmyJust("??")n .subscribe { print($0) }n .addDisposableTo(disposeBag)n

next(??)ncompletedn

range

range就是創建一個sequence,他會發出這個範圍中的從開始到結束的所有事件

let disposeBag = DisposeBag()nnObservable.range(start: 1, count: 10)n .subscribe { print($0) }n .addDisposableTo(disposeBag)n

next(1)nnext(2)nnext(3)nnext(4)nnext(5)nnext(6)nnext(7)nnext(8)nnext(9)nnext(10)ncompletedn

repeatElement

創建一個sequence,發出特定的事件n次

let disposeBag = DisposeBag()nnObservable.repeatElement("??")n .take(3)n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

generate

generate是創建一個可觀察sequence,當初始化的條件為true的時候,他就會發出所對應的事件

let disposeBag = DisposeBag()nnObservable.generate(n initialState: 0,n condition: { $0 < 3 },n iterate: { $0 + 1 }n )n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

0n1n2n

deferred

deferred會為每一為訂閱者observer創建一個新的可觀察序列

下面例子中每次進行subscribe的時候都會去創建一個新的deferredSequence,所以Emitting會列印兩遍。

let disposeBag = DisposeBag()nvar count = 1nnlet deferredSequence = Observable<String>.deferred {n print("Creating (count)")n count += 1nn return Observable.create { observer inn print("Emitting...")n observer.onNext("??")n observer.onNext("??")n observer.onNext("??")n return Disposables.create()n }n}nndeferredSequencen .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)nndeferredSequencen .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

Creating 1nEmitting...n??n??n??nCreating 2nEmitting...n??n??n??n

error

創建一個可觀察序列,但不發出任何正常的事件,只發出error事件並結束

let disposeBag = DisposeBag()nnObservable<Int>.error(TestError.test)n .subscribe { print($0) }n .addDisposableTo(disposeBag)n

error(test)n

doOn

doOn我感覺就是在直接onNext處理時候,先執行某個方法,doOnNext( :)方法就是在subscribe(onNext:)前調用,doOnCompleted(:)就是在subscribe(onCompleted:)前面調用的。

let disposeBag = DisposeBag()nnObservable.of("??", "??", "??", "??")n .do(onNext: { print("Intercepted:", $0) }, onError: { print("Intercepted error:", $0) }, onCompleted: { print("Completed") })n .subscribe(onNext: { print($0) },onCompleted: { print("結束") })n .addDisposableTo(disposeBag)n

Intercepted: ??n??nIntercepted: ??n??nIntercepted: ??n??nIntercepted: ??n??nCompletedn結束n

學會使用Subjects

Subjet是observable和Observer之間的橋樑,一個Subject既是一個Obserable也是一個Observer,他既可以發出事件,也可以監聽事件。

PublishSubject

當你訂閱PublishSubject的時候,你只能接收到訂閱他之後發生的事件。subject.onNext()發出onNext事件,對應的還有onError()和onCompleted()事件

let disposeBag = DisposeBag()nlet subject = PublishSubject<String>()nnsubject.addObserver("1").addDisposableTo(disposeBag)nsubject.onNext("??")nsubject.onNext("??")nnsubject.addObserver("2").addDisposableTo(disposeBag)nsubject.onNext("???")nsubject.onNext("???")n

Subscription: 1 Event: next(??)nSubscription: 1 Event: next(??)nSubscription: 1 Event: next(???)nSubscription: 2 Event: next(???)nSubscription: 1 Event: next(???)nSubscription: 2 Event: next(???)n

ReplaySubject

當你訂閱ReplaySubject的時候,你可以接收到訂閱他之後的事件,但也可以接受訂閱他之前發出的事件,接受幾個事件取決與bufferSize的大小

let disposeBag = DisposeBag()nlet subject = ReplaySubject<String>.create(bufferSize: 1)nnsubject.addObserver("1").addDisposableTo(disposeBag)nsubject.onNext("??")nsubject.onNext("??")nnsubject.addObserver("2").addDisposableTo(disposeBag)nsubject.onNext("???")nsubject.onNext("???")n

Subscription: 1 Event: next(??)nSubscription: 1 Event: next(??)nSubscription: 2 Event: next(??) //訂閱之後還可以接受一次前面發出的事件nSubscription: 1 Event: next(???)nSubscription: 2 Event: next(???)nSubscription: 1 Event: next(???)nSubscription: 2 Event: next(???)n

BehaviorSubject

當你訂閱了BehaviorSubject,你會接受到訂閱之前的最後一個事件。

let disposeBag = DisposeBag()nlet subject = BehaviorSubject(value: "??")nnsubject.addObserver("1").addDisposableTo(disposeBag)nsubject.onNext("??")nsubject.onNext("??")nnsubject.addObserver("2").addDisposableTo(disposeBag)nsubject.onNext("???")nsubject.onNext("???")nnsubject.addObserver("3").addDisposableTo(disposeBag)nsubject.onNext("??")nsubject.onNext("??")n

Subscription: 1 Event: next(??)nSubscription: 1 Event: next(??)nSubscription: 1 Event: next(??)nSubscription: 2 Event: next(??) //訂閱之前的最後一個事件nSubscription: 1 Event: next(???)nSubscription: 2 Event: next(???)nSubscription: 1 Event: next(???)nSubscription: 2 Event: next(???)nSubscription: 3 Event: next(???) //訂閱之前的最後一個事件nSubscription: 1 Event: next(??)nSubscription: 3 Event: next(??)nSubscription: 2 Event: next(??)nSubscription: 1 Event: next(??)nSubscription: 3 Event: next(??)nSubscription: 2 Event: next(??)n

PublishSubject, ReplaySubject和BehaviorSubject是不會自動發出completed事件的。

Variable

Variable是BehaviorSubject一個包裝箱,就像是一個箱子一樣,使用的時候需要調用asObservable()拆箱,裡面的value是一個BehaviorSubject,他不會發出error事件,但是會自動發出completed事件。

let disposeBag = DisposeBag()nlet variable = Variable("??")nnvariable.asObservable().addObserver("1").addDisposableTo(disposeBag)nvariable.value = "??"nvariable.value = "??"nnvariable.asObservable().addObserver("2").addDisposableTo(disposeBag)nvariable.value = "???"nvariable.value = "???"n

Subscription: 1 Event: next(??)nSubscription: 1 Event: next(??)nSubscription: 1 Event: next(??)nSubscription: 2 Event: next(??)nSubscription: 1 Event: next(???)nSubscription: 2 Event: next(???)nSubscription: 1 Event: next(???)nSubscription: 2 Event: next(???)nSubscription: 1 Event: completednSubscription: 2 Event: completedn

聯合操作

聯合操作就是把多個Observable流合成單個Observable流

startWith

在發出事件消息之前,先發出某個特定的事件消息。比如發出事件2 ,3然後我startWith(1),那麼就會先發出1,然後2 ,3.

let disposeBag = DisposeBag()nnObservable.of("2", "3")n .startWith("1")n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

1n2n3n

merge

合併兩個Observable流合成單個Observable流,根據時間軸發出對應的事件

let disposeBag = DisposeBag()nnlet subject1 = PublishSubject<String>()nlet subject2 = PublishSubject<String>()nnObservable.of(subject1, subject2)n .merge()n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)nnsubject1.onNext("???")nnsubject1.onNext("???")nnsubject2.onNext("①")nnsubject2.onNext("②")nnsubject1.onNext("??")nnsubject2.onNext("③")n

???n???n①n②n??n③n

zip

綁定超過最多不超過8個的Observable流,結合在一起處理。注意Zip是一個事件對應另一個流一個事件。

let disposeBag = DisposeBag()nnlet stringSubject = PublishSubject<String>()nlet intSubject = PublishSubject<Int>()nnObservable.zip(stringSubject, intSubject) { stringElement, intElement inn "(stringElement) (intElement)"n }n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)nnstringSubject.onNext("???")nstringSubject.onNext("???")nnintSubject.onNext(1)nnintSubject.onNext(2)nnstringSubject.onNext("??")nintSubject.onNext(3)n

??? 1 將stringSubject和intSubject壓縮到一起共同處理n??? 2n?? 3n

combineLatest

綁定超過最多不超過8個的Observable流,結合在一起處理。和Zip不同的是combineLatest是一個流的事件對應另一個流的最新的事件,兩個事件都會是最新的事件,可將下圖與Zip的圖進行對比。

let disposeBag = DisposeBag()nnlet stringSubject = PublishSubject<String>()nlet intSubject = PublishSubject<Int>()nnObservable.combineLatest(stringSubject, intSubject) { stringElement, intElement inn "(stringElement) (intElement)"n }n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)nnstringSubject.onNext("???")nnstringSubject.onNext("???")nintSubject.onNext(1)nnintSubject.onNext(2)nnstringSubject.onNext("??")n

??? 1n??? 2n?? 2n

switchLatest

switchLatest可以對事件流進行轉換,本來監聽的subject1,我可以通過更改variable裡面的value更換事件源。變成監聽subject2了

let disposeBag = DisposeBag()nnlet subject1 = BehaviorSubject(value: "??")nlet subject2 = BehaviorSubject(value: "??")nnlet variable = Variable(subject1)nnvariable.asObservable()n .switchLatest()n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)nnsubject1.onNext("??")nsubject1.onNext("??")nnvariable.value = subject2nnsubject1.onNext("??")nnsubject2.onNext("??")nvariable.value = subject1nsubject2.onNext("田騰飛")nsubject1.onNext("沸騰天")n

??n??n??n??n??n??n沸騰天n

變換操作

map

通過傳入一個函數閉包把原來的sequence轉變為一個新的sequence的操作

let disposeBag = DisposeBag()nObservable.of(1, 2, 3)n .map { $0 * $0 }n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

1 每一個元素自己相乘n4n9n

flatMap

將一個sequence轉換為一個sequences,當你接收一個sequence的事件,你還想接收其他sequence發出的事件的話可以使用flatMap,她會將每一個sequence事件進行處理以後,然後再以一個sequence形式發出事件。而且flatMap有一次拆包動作,請看代碼解析。

let disposeBag = DisposeBag()nnstruct Player {n var score: Variable<Int> //裡面是一個Variablen}nnlet ???? = Player(score: Variable(80)) nlet ???? = Player(score: Variable(90))nlet ?? = Player(score: Variable(550))nnlet player = Variable(????) //將player轉為Variablennplayer.asObservable() //拆箱轉成可被監聽的sequencen .flatMap { $0.score.asObservable() } // flatMap有一次拆包動作,$0本來應該是一個BehaviorSubject類型,但是直接訪問了score。所以猜想flatMap對behaviorSubject進行了onNext拆包取數據n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)nn????.score.value = 85nnplayer.value = ???? //更換了value,相當於又添加了一個sequence,兩個sequence都可以接收nn????.score.value = 95n????.score.value = 222nplayer.value = ??nn????.score.value = 100n

80n85n90n95n222n550n100n

flatMapLatest

flatMapLatest只會接收最新的value事件,將上例改為flatMapLatest。結果為

80n85n90n550n

scan

scan就是給一個初始化的數,然後不斷的拿前一個結果和最新的值進行處理操作。

let disposeBag = DisposeBag()nnObservable.of(10, 100, 1000)n .scan(1) { aggregateValue, newValue inn aggregateValue + newValuen }n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

11n111n1111n

過濾和約束

filter

filter很好理解,就是過濾掉某些不符合要求的事件

let disposeBag = DisposeBag()nnObservable.of(n "??", "??", "??",n "??", "??", "??",n "??", "??", "??")n .filter {n $0 == "??"n }n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

??n??n??n

distinctUntilChanged

distinctUntilChanged就是當下一個事件與前一個事件是不同事件的事件才進行處理操作

let disposeBag = DisposeBag()nnObservable.of("??", "??", "??", "??", "??", "??", "??")n .distinctUntilChanged()n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

??n??n??n??n??n

elementAt

只處理在指定位置的事件

let disposeBag = DisposeBag()nnObservable.of("??", "??", "??", "??", "??", "??")n .elementAt(3)n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

??n

single

找出在sequence只發出一次的事件,如果超過一個就會發出error錯誤

Observable.of("??", "??", "??", "??", "??", "??")n .single()n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

?? //單一信號超過了一個nReceived unhandled error: /var/folders/hz/v15ld5mj0nqf83d21j13y0tw0000gn/T/./lldb/7229/playground107.swift:69:__lldb_expr_107 -> Sequence contains more than one element.n

Observable.of("??", "??", "??", "??", "??", "??")n .single { $0 == "??" } //青蛙只有一個,completedn .subscribe { print($0) }n .addDisposableTo(disposeBag)n

Observable.of("??", "??", "??", "??", "??", "??")n .single { $0 == "??" } //兔子有兩個,會發出errorn .subscribe { print($0) }n .addDisposableTo(disposeBag)n

Observable.of("??", "??", "??", "??", "??", "??")n .single { $0 == "??" } //沒有藍色球,會發出errorn .subscribe { print($0) }n .addDisposableTo(disposeBag)n

take

只處理前幾個事件信號,

let disposeBag = DisposeBag()nnObservable.of("??", "??", "??", "??", "??", "??")n .take(3)n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

??n??n??n

takeLast

只處理後幾個事件信號

let disposeBag = DisposeBag()nnObservable.of("??", "??", "??", "??", "??", "??")n .takeLast(3)n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

??n??n??n

takeWhile

當條件滿足的時候進行處理

let disposeBag = DisposeBag()nnObservable.of(1, 2, 3, 4, 5, 6)n .takeWhile { $0 < 4 }n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

1n2n3n

takeUntil

接收事件消息,直到另一個sequence發出事件消息的時候。

let disposeBag = DisposeBag()nnlet sourceSequence = PublishSubject<String>()nlet referenceSequence = PublishSubject<String>()nnsourceSequencen .takeUntil(referenceSequence)n .subscribe { print($0) }n .addDisposableTo(disposeBag)nnsourceSequence.onNext("??")nsourceSequence.onNext("??")nsourceSequence.onNext("??")nnreferenceSequence.onNext("??") //停止接收消息nnsourceSequence.onNext("??")nsourceSequence.onNext("??")nsourceSequence.onNext("??")n

next(??)nnext(??)nnext(??)ncompletedn

skip

取消前幾個事件

let disposeBag = DisposeBag()nnObservable.of("??", "??", "??", "??", "??", "??")n .skip(2)n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

??n??n??n??n

skipWhile

滿足條件的事件消息都取消

let disposeBag = DisposeBag()nnObservable.of(1, 2, 3, 4, 5, 6)n .skipWhile { $0 < 4 }n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

4n5n6n

skipWhileWithIndex

滿足條件的都被取消,傳入的閉包同skipWhile有點區別而已

let disposeBag = DisposeBag()nnObservable.of("??", "??", "??", "??", "??", "??")n .skipWhileWithIndex { element, index inn index < 3n }n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

skipUntil

直到某個sequence發出了事件消息,才開始接收當前sequence發出的事件消息

let disposeBag = DisposeBag()nnlet sourceSequence = PublishSubject<String>()nlet referenceSequence = PublishSubject<String>()nnsourceSequencen .skipUntil(referenceSequence)n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)nnsourceSequence.onNext("??")nsourceSequence.onNext("??")nsourceSequence.onNext("??")nnreferenceSequence.onNext("??")nnsourceSequence.onNext("??")nsourceSequence.onNext("??")nsourceSequence.onNext("??")n}n

數學操作

toArray

將sequence轉換成一個array,並轉換成單一事件信號,然後結束

let disposeBag = DisposeBag()nnObservable.range(start: 1, count: 10)n .toArray()n .subscribe { print($0) }n .addDisposableTo(disposeBag)n

next([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])ncompletedn

reduce

用一個初始值,對事件數據進行累計操作。reduce接受一個初始值,和一個操作符號

let disposeBag = DisposeBag()nnObservable.of(10, 100, 1000)n .reduce(1, accumulator: +)n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

1111n

concat

concat會把多個sequence和並為一個sequence,並且當前面一個sequence發出了completed事件,才會開始下一個sequence的事件。

在第一sequence完成之前,第二個sequence發出的事件都會被忽略,但會接收一完成之前的二發出的最後一個事件。不好解釋,看例子說明

let disposeBag = DisposeBag()nnlet subject1 = BehaviorSubject(value: "??")nlet subject2 = BehaviorSubject(value: "??")nnlet variable = Variable(subject1)nnvariable.asObservable()n .concat()n .subscribe { print($0) }n .addDisposableTo(disposeBag)nnsubject1.onNext("??")nsubject1.onNext("??")nnvariable.value = subject2nnnsubject2.onNext("??") //1完成前,會被忽略nsubject2.onNext("teng") //1完成前,會被忽略nsubject2.onNext("fei") //1完成前的最後一個,會被接收nnsubject1.onCompleted()nnsubject2.onNext("??")n

next(??)nnext(??)nnext(??)nnext(fei)nnext(??)n

連接性操作

Connectable Observable有訂閱時不開始發射事件消息,而是僅當調用它們的connect()方法時。這樣就可以等待所有我們想要的訂閱者都已經訂閱了以後,再開始發出事件消息,這樣能保證我們想要的所有訂閱者都能接收到事件消息。其實也就是等大家都就位以後,開始發出消息。

publish

將一個正常的sequence轉換成一個connectable sequence

let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance)n .publish()nn_ = intSequencen .subscribe(onNext: { print("Subscription 1:, Event: ($0)") })nndelay(2) { _ = intSequence.connect() } //相當於把事件消息推遲了兩秒nndelay(4) {n _ = intSequencen .subscribe(onNext: { print("Subscription 2:, Event: ($0)") })n}nndelay(6) {n _ = intSequencen .subscribe(onNext: { print("Subscription 3:, Event: ($0)") })n}n

Subscription 1:, Event: 0nSubscription 1:, Event: 1nSubscription 2:, Event: 1nSubscription 1:, Event: 2nSubscription 2:, Event: 2nSubscription 1:, Event: 3nSubscription 3:, Event: 3nSubscription 2:, Event: 3nSubscription 1:, Event: 4nSubscription 3:, Event: 4n

replay

將一個正常的sequence轉換成一個connectable sequence,然後和replaySubject相似,能接收到訂閱之前的事件消息。

let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance)n .replay(5) //接收到訂閱之前的5條事件消息nn_ = intSequencen .subscribe(onNext: { print("Subscription 1:, Event: ($0)") })nndelay(2) { _ = intSequence.connect() }nndelay(4) {n _ = intSequencen .subscribe(onNext: { print("Subscription 2:, Event: ($0)") })n}nndelay(8) {n _ = intSequencen .subscribe(onNext: { print("Subscription 3:, Event: ($0)") })n}n

multicast

將一個正常的sequence轉換成一個connectable sequence,並且通過特性的subject發送出去,比如PublishSubject,或者replaySubject,behaviorSubject等。不同的Subject會有不同的結果。

let subject = PublishSubject<Int>()nn_ = subjectn .subscribe(onNext: { print("Subject: ($0)") })nnlet intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance)n .multicast(subject)nn_ = intSequencen .subscribe(onNext: { print("tSubscription 1:, Event: ($0)") })nndelay(2) { _ = intSequence.connect() }nndelay(4) {n _ = intSequencen .subscribe(onNext: { print("tSubscription 2:, Event: ($0)") })n}n

錯誤處理

catchErrorJustReturn

遇到error事件的時候,就return一個值,然後結束

let disposeBag = DisposeBag()nnlet sequenceThatFails = PublishSubject<String>()nnsequenceThatFailsn .catchErrorJustReturn("??")n .subscribe { print($0) }n .addDisposableTo(disposeBag)nnsequenceThatFails.onNext("??")nsequenceThatFails.onNext("??")nsequenceThatFails.onNext("??")nsequenceThatFails.onNext("??")nsequenceThatFails.onError(TestError.test)n

next(??)nnext(??)nnext(??)nnext(??)nnext(??)ncompletedn

catchError

捕獲error進行處理,可以返回另一個sequence進行訂閱

let disposeBag = DisposeBag()nnlet sequenceThatFails = PublishSubject<String>()nlet recoverySequence = PublishSubject<String>()nnsequenceThatFailsn .catchError {n print("Error:", $0)n return recoverySequencen }n .subscribe { print($0) }n .addDisposableTo(disposeBag)nnsequenceThatFails.onNext("??")nsequenceThatFails.onNext("??")nsequenceThatFails.onNext("??")nsequenceThatFails.onNext("??")nsequenceThatFails.onError(TestError.test)nnrecoverySequence.onNext("??")n

next(??)nnext(??)nnext(??)nnext(??)nError: testnnext(??)n

retry

遇見error事件可以進行重試,比如網路請求失敗,可以進行重新連接

let disposeBag = DisposeBag()nvar count = 1nnlet sequenceThatErrors = Observable<String>.create { observer inn observer.onNext("??")n observer.onNext("??")n observer.onNext("??")nn if count == 1 {n observer.onError(TestError.test)n print("Error encountered")n count += 1n }nn observer.onNext("??")n observer.onNext("??")n observer.onNext("??")n observer.onCompleted()nn return Disposables.create()n}nnsequenceThatErrorsn .retry(3) //不傳入數字的話,只會重試一次n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

debug

debug

列印所有的訂閱, 事件和disposals

sequenceThatErrorsn .retry(3)n .debug()n .subscribe(onNext: { print($0) })n .addDisposableTo(disposeBag)n

RxSwift.Resources.total

查看RxSwift所有資源的佔用

print(RxSwift.Resources.total)n

啊,文章終於結束,這篇文章比較長,基本上涵蓋了官方文檔所有的概念,其中不免有些錯誤與疏漏,希望能在你學習RxSwift的時候能有一些參考價值吧!!!

閱讀原文


推薦閱讀:

MVVM模式中處理業務邏輯是應該在M中還是VM中?
Vue.js會一直維護嗎?
vuejs ui庫優劣勢分析和選擇?
KnockoutJs怎麼樣?
主流的MVVM框架中如何做國際化?

TAG:Swift编程 | MVVM | FunctionalReactiveProgramming |