前言
最近在學(xué)習(xí)swift眉厨,看著喵神翻譯的《Swift進(jìn)階》滑黔,一直看著頗感疲乏僻他,于是想邊學(xué)邊實踐來讓自己不那么的犯困宵距。畢竟紙上得來終覺淺嘛所以我就順手入了Raywenderlich上的RxSwift的書籍(這是一本好書,延續(xù)了Raywenderlich一貫的風(fēng)格——講課與動手相結(jié)合吨拗,每一章都有一個樣例程序讓你一步步跟著去實現(xiàn)满哪,結(jié)尾還會有challenge)。并且丢胚,這也是我在簡書的第一篇文章翩瓜,主要是我的手提上的hexo掛了,掛在github上的博客也沒法更新了携龟,弄了兩個星期都沒弄好兔跌,沒轍了。然而學(xué)習(xí)仍在繼續(xù)峡蟋,筆記也是要做的坟桅,所以就先來簡書寫寫吧
然后圍繞著RxSwift這個主題华望,估計我會寫上好幾篇文章,基本上每個小的主題也都會跟著《RxSwift--Reactive Programming with Swift》這本書來仅乓,你也會看到很多這本書的影子赖舟。那么如果你沒有這本書,通過我的文章來一窺RxSwift的究竟我想也是可以的夸楣,假如你有買這本書宾抓,在學(xué)習(xí)的路上有什么不懂的可以留言評論互相交流,如果你看到我的博客有什么不對的地方也希望指出改正豫喧!提前謝過石洗!
RxSwift簡介
我對RxSwift的了解并不多,但就依我目前的了解紧显,RxSwift主要是提供了一種在Swift語言下可以輕易寫出響應(yīng)式函數(shù)式的功能實現(xiàn)讲衫。主要就是方便了我們現(xiàn)在的多線程處理獲取數(shù)據(jù)并進(jìn)行處理的這么一個流程。說到后臺獲取數(shù)據(jù)孵班,你的第一反應(yīng)大概是GCD
, OperationQueue
, Delegate
, NotificationCenter
. 為此你不得不實現(xiàn)一些協(xié)議涉兽,寫多幾個方法,甚至要實現(xiàn)一些類篙程。然而RxSwift和RxCocoa的出現(xiàn)讓我們擺脫了這些枷畏。讓你可以在無數(shù)的.function()
調(diào)用函數(shù)中立即做出對即將獲取到的數(shù)據(jù)的處理。而且它最基礎(chǔ)的實現(xiàn)房午,源自于Observable
矿辽,因為Observable
就像一條數(shù)據(jù)流,當(dāng)新的數(shù)據(jù)出現(xiàn)郭厌,它就會通知它的Subscriber
去做對應(yīng)的處理袋倔。總而言之折柠,比起曾經(jīng)你在Cocoa Touch
上所用到的方式宾娜,使用RxSwift后,你會看到一片不一樣的天地扇售。
RxSwift安裝指南
詳見官網(wǎng)
什么是Observable前塔?
Observable
我也不知道中文怎么翻譯,直譯一下就是可觀察的承冰,但它通常都會被實例化华弓,于是我稱它為可觀察的實例。
實質(zhì)上困乒,它就是一個Sequence
(序列)寂屏,序列分為有窮序列和無窮序列,主要就是用來形成一條數(shù)據(jù)流。說到有窮的數(shù)據(jù)流迁霎,我們不難想到通過網(wǎng)絡(luò)來獲取一張圖片這一個過程吱抚,數(shù)據(jù)是有限的,圖片下載完了考廉,序列也就迎來閉合了秘豹;而說到無窮序列,一般就是我們對UI的監(jiān)測可能是無窮的昌粤,比如某個手勢既绕、某次按鈕的點擊、橫豎屏切換等等婚苹。
而你所有的操作產(chǎn)生的數(shù)據(jù)都會通過Observable
傳輸——所以實質(zhì)上Observable
就是一條數(shù)據(jù)流岸更。
Observable的三種事件
Observable
里有三種事件——next
, completed
, error
:
-
next
事件主要是當(dāng)Observable
里出現(xiàn)新的數(shù)據(jù)時會發(fā)出的事件,同時該事件會攜帶新的數(shù)據(jù)對象膊升。 -
completed
事件是當(dāng)Observable
不再有新的數(shù)據(jù)出現(xiàn),Observable
被標(biāo)記完成谭企,并且將數(shù)據(jù)流終結(jié)(terminate)廓译。 -
error
事件是指當(dāng)數(shù)據(jù)流遇到了錯誤會發(fā)出的事件,該事件也會導(dǎo)致Observable
被終結(jié)债查。
值得一提的是非区,被終結(jié)的Observable
不會再有任何的事件發(fā)出。
Observable如何創(chuàng)建盹廷?
just, of, from
Observable
類自帶三個方法來創(chuàng)建一個Observable
實例征绸,分別使用于不同的情況。of方法毫無疑問是最常用也最方便的一個方法俄占。但是現(xiàn)在還是把每一個都做一個簡單的介紹吧管怠!
just
方法所創(chuàng)建出的Observable
實例可以說是和just的字面意義非常的相近了,因為just
僅能傳入一個參數(shù)作為Observable
內(nèi)所包含的元素來創(chuàng)建一個實例缸榄〔吵冢考慮以下代碼片段:
let one = 1
let two = 2
let variable = Observable.just(one)
這就是用just
來創(chuàng)建一個Observable
實例的方式。如果你也run了上面的代碼甚带,你可以用option+鼠標(biāo)左鍵點擊上面的變量variable
她肯,你可以發(fā)現(xiàn)編譯器的類型推斷為Observable<Int>。是的鹰贵,just
, of
方法接受的參數(shù)都是泛型的晴氨。
of
方法可以接受多個參數(shù)來創(chuàng)建實例〉锸洌考慮以下代碼片段:
let one = 1
let two = 2
let three = 3
let variable = Observable.of(one, two , three)
let variable2 = Observable.of([one, two, three])
回顧一下我之前說的籽前,Observable
實質(zhì)上就是一條數(shù)據(jù)流,所有的創(chuàng)建方法所傳入的參數(shù)都是這條數(shù)據(jù)流上的元素。上面的那段代碼聚假,對于variable
變量而言块蚌,one
, two
, three
就是里面的元素,對于variable2
而言膘格,數(shù)組[one, two, three]
就是里面的元素峭范。option+click一下,variable
被推斷成為Observable<Int>
瘪贱,variable2
被推斷成為Observable<[Int]>
纱控。這里為什么要看似多此一舉的聲明一個variable2
呢?因為這和接下來的from
方法有關(guān)系菜秦,為了理清楚兩個創(chuàng)建方法的不同甜害,就在這里先聲明一個這樣的變量先。
from
方法只接收數(shù)組作為參數(shù)球昨,并抽取出數(shù)組里的元素來作為數(shù)據(jù)流中的元素尔店。代碼如下:
let variable = Observable.from([1, 2, 3])
在這里,如果你用option+click去看variable
的推斷類型的話主慰,你可以發(fā)現(xiàn)它的推斷類型是Observable<Int>
嚣州,和of
不同的是,of
創(chuàng)建的實例以數(shù)組作為元素共螺;from
則以1
, 2
, 3
作為元素该肴。
range方法
利用range
我們可以快速的創(chuàng)建一個包含一段范圍內(nèi)的正整數(shù)的數(shù)據(jù)流。它接受start
和count
作為參數(shù)來表示一段創(chuàng)建的范圍藐不。
let observable = Observable<Int>.range(start: 1, count: 10)
empty()——創(chuàng)建一個空的可觀察的實例
為了讓接下來的創(chuàng)建方法更加地容易理解匀哄,我不得不把稍后才會講到訂閱(subscribe)方法提前使用,但是我相信你能看懂雏蛮,至于詳盡的使用方式涎嚼,就見下文吧!
empty()
方法主要是創(chuàng)建了一個空的數(shù)據(jù)流底扳,里面沒有任何的元素铸抑,所以它不會發(fā)出任何的next
事件,它只會發(fā)出一個completed
事件衷模,然后終結(jié)鹊汛。還有一點是,沒有被訂閱的Observable
實例并不會發(fā)出任何事件阱冶,也不會終結(jié)刁憋,所以你看到上面所創(chuàng)建的數(shù)據(jù)流,其中的數(shù)據(jù)也并沒有被處理木蹬。
直到訂閱者出現(xiàn)至耻,數(shù)據(jù)流就會開始向訂閱者發(fā)送事件了!
let observable = Observable<Void>.empty()
observable
.subscribe(
onNext: {element in
print(element)
},
onCompleted: {
print("completed")
})
/*
輸出:
completed
*/
這段代碼首先用empty()
創(chuàng)建了一個不含元素的Observable<Void>
實例,然后訂閱了這個實例的next
事件和completed
事件尘颓,由于這條數(shù)據(jù)流不含任何元素走触,所以它直接向訂閱者發(fā)送了一個completed
事件然后就終結(jié)了。
never()——創(chuàng)建一個代表無盡時長的數(shù)據(jù)流
never()
方法創(chuàng)建了一個不會發(fā)出任何事件也不會終結(jié)的Observable
實例疤苹,盡管如此互广,它也可以代表一段無限(相對無限)的時長。但是卧土,如果它不能發(fā)出任何事件惫皱,那又有什么用呢?其實它可以配合do
方法來做一些工作尤莺,它還可以被subscribe
到dispose
“事件”旅敷,來判斷在當(dāng)前的環(huán)境下,never()是什么時候被回收的颤霎。當(dāng)然媳谁,dispose
和do
目前都沒有介紹,詳情見下文友酱。
Subscribe
訂閱一個Observable
實例主要有兩個方法韩脑,talk is cheap, show you the code.
let observable = Observable.of(1, 2, 3)
//1
observable.subscribe({ event in
print(event)
})
//2
observable.subscribe(onNext: { element in
print(element)
})
/*
輸出結(jié)果:
next(1)
next(2)
next(3)
completed
1
2
3
*/
這段代碼里用了兩個方法來subscribe
一個Observable
對象,方法1直接subscribe
了所有的事件粹污,在回調(diào)的block里獲取到的參數(shù)就是事件本身;而方法2則提供了幾個可選的參數(shù)比如onNext
, onError
, onCompleted
, onDisposed
來訂閱到不同的事件首量,而我提供的樣例里訂閱的是next
事件壮吩。next
事件的回調(diào)block會傳入當(dāng)前next
事件所攜帶的元素。
dispose和DisposeBag——讓訂閱者釋放
如果你足夠細(xì)心的話加缘,你會發(fā)現(xiàn)每次subscribe
方法調(diào)用后都會返回一個Disposable
對象鸭叙,代表著每一次訂閱都是需要被釋放的,遺憾的是拣宏,這并不由ARC進(jìn)行管理沈贝,而是由RxSwift來管理。然而勋乾,RxSwift也沒有提供自動釋放的機(jī)制宋下,始終是需要你手動釋放的。
一種方法是調(diào)用Disposable
的dispose()
方法辑莫。
let observable = Observable.of("A", "B", "C")
observable
.subscribe(onNext: { element in
print(element)
}, onCompleted: {
print("completed")
}, onDisposed: {
print("disposed")
})
.dispose()
/*
輸出結(jié)果:
A
B
C
completed
disposed
*/
每次訂閱都要單獨管理它的釋放是非常冗余的(書里原話学歧,但實質(zhì)上我也沒感覺和加到垃圾袋里有多大差別,反正也是每次要多調(diào)用一個函數(shù))各吨,所以RxSwift提供了一個類似于Auto Release Pool
的釋放機(jī)制枝笨,稱為DisposeBag
。被加到DisposeBag
的Disposable
對象會在DisposeBag
將要釋放的時候被逐一調(diào)用dispose()
。它的使用是這樣的:
let disposeBag = DisposeBag()
Observable.of("A", "B", "C")
.subscribe { print($0) }
.addDisposableTo(disposeBag)
/*
輸出結(jié)果:
next(A)
next(B)
next(C)
completed
實際上横浑,從上面兩段的代碼我們可以看出來剔桨,雖然subscribe
可以訂閱到一次訂閱被釋放時的disposed
"事件",是的徙融,我這里打了雙引號洒缀,因為它和next
, error
, completed
不一樣。從第二段代碼來看就很明了了张咳,并沒有打印出disposed
相關(guān)的事件帝洪。
create——創(chuàng)建一條可自定義事件的數(shù)據(jù)流
create
嘛,功能就像標(biāo)題說的那樣脚猾,創(chuàng)建一個Observable
對象葱峡,但是里面的事件可以有你來自定義。
enum MyError: Error {
case anError
}
let disposeBag = DisposeBag()
Observable<String>.create { observer in
observer.onNext("1")
observer.onError(MyError.anError)
observer.onCompleted()
observer.onNext("?")
return Disposables.create() //return a disposable to represent a subscription
}
.subscribe(
onNext: { print($0) },
onError: { print($0) },
onCompleted: { print("completed") },
onDisposed: { print("Disposed") }
)
.addDisposableTo(disposeBag)
/*
輸出結(jié)果:
1
anError
Disposed
*/
正如代碼所示龙助,上面的create
為一個observer
添加了next
, error
, completed
, next
事件砰奕,但是很顯然它輸出到error
事件就終結(jié)了,后面的事件也不會再發(fā)出提鸟。
如果你想的話军援,你可以標(biāo)注或者移位上面的代碼,來看看不同的輸出称勋。
deferred——創(chuàng)建一個可以生成不同的Observable對象的工廠
deferred
就是一個Observable
的工廠胸哥,你可以在里面定制幾條不同的數(shù)據(jù)流,從而提供給外部不同的訂閱赡鲜,代碼如下:
let disposeBag = DisposeBag()
var flip = false
let factory: Observable<Int> = Observable.deferred {
flip = !flip
if flip {
return Observable.of(1, 2, 3)
}
else {
return Observable.of(4, 5, 6)
}
}
for _ in 0...3 {
factory.subscribe(onNext: { print($0, terminator:"") })
.addDisposableTo(disposeBag)
print()
}
/*
輸出結(jié)果:
123
456
123
456
*/
上面的代碼就是空厌,我在一個deferred
工廠里定義了兩條不同的數(shù)據(jù)流,分別是1, 2, 3
和4, 5, 6
银酬,設(shè)置了一個翻轉(zhuǎn)變量flip
嘲更,隨著每次訂閱,奇數(shù)次的訂閱訂閱到的是1, 2, 3
數(shù)據(jù)流揩瞪,而4, 5, 6
數(shù)據(jù)流則是由偶數(shù)次的訂閱訂閱到赋朦。
好了,這就是本章節(jié)的全部內(nèi)容了李破。