最近花了一點時間去學(xué)習(xí)ReactiveSwift(以下稱RAS),這是一款基于ReactiveCocoa開發(fā)的Swift框架,由于這個框架大量使用了函數(shù)式編程和響應(yīng)式編程的結(jié)合,所以它也被稱之為函數(shù)相應(yīng)式編程 -- RFP(Functional Reactive Programming)。在編程的時候,RAS可以幫助我們:
-
簡化響應(yīng)式函數(shù)的模式
在Swift中,我們有幾種響應(yīng)式的開發(fā)模式:target-action、代理、通知中心、KVO等。以上每個模式對應(yīng)的場景不同,我們需要根據(jù)場景選擇合適的模式。RAS的整合了所有的模式的特點,開辟了一套
事件流(信號)-觀察者(發(fā)送)
的模式,將以上種種模式替代。
-
高度聚集的代碼實現(xiàn)
想想我們使用閉包的原因 -- 將相關(guān)代碼在同一環(huán)境中實現(xiàn)異步執(zhí)行,提升代碼的可讀性。RAS將這種思想用到極致。
-
與MVVM設(shè)計模式結(jié)合使用寫出優(yōu)雅簡潔的代碼
為了簡化MVC中因項目逐漸龐大導(dǎo)致Controller中代碼的沉冗,MVVM模式被我們喜歡,但是它帶來的另一個問題是V(View)和VM(viewModel)之間的數(shù)據(jù)傳遞過于復(fù)雜。而RAS的數(shù)據(jù)綁定解決了這個問題,我們使用這兩者的結(jié)合,能夠?qū)懗龊軆?yōu)雅的代碼。
所以學(xué)習(xí)RAS對我們寫出更加優(yōu)雅簡潔、通俗易懂的代碼有很大的幫助。
我之前并沒有很豐富的函數(shù)式和相應(yīng)式編程的經(jīng)驗,所以在開始學(xué)習(xí)RAS的時候感覺曲線陡峭,在這里很幸運(yùn)得看到了青玉伏案的博客,他的博文在我學(xué)習(xí)RAS的路上給予了巨大的幫助。
之所以寫這個文章,是因為目前RAS的更新?lián)Q代很快,包括前幾次的大更新(RAS 3.0),為了使用Swift3的特性,RAS與之前的版本差異很大。以前很多前人寫過的博客、技術(shù)分享等都不再適用當(dāng)前的版本,對于其他人的學(xué)習(xí)帶來很大的迷惑性。而在這一系列的文章中將分享我自己學(xué)習(xí)的收獲吧,希望可以幫助到與我一樣正在學(xué)習(xí)RAS的人,當(dāng)然,作為正在學(xué)習(xí)的新人,有些地方理解不夠出現(xiàn)紕漏甚至錯誤都難以避免,希望可以多多討論。
這是系列文章的閱讀需要對Swift的一些特性有所了解,比如Swift中的枚舉關(guān)聯(lián)值、元組、類泛型、方法泛型等。然后你可能還需要了解一些有關(guān)于迭代器的知識。當(dāng)然并非需要很專業(yè)的知識,只要能夠理解明白即可。
1.進(jìn)入文章正題—— 信號(Signal)
RAS中,信號貫穿整個框架。信號內(nèi)部包含了一個發(fā)送器,我們可以通過發(fā)送器發(fā)送一些內(nèi)容
,這些內(nèi)容
即是框架中最基本的單元--事件。除了發(fā)送器,信號中還包含了一個裝有若干個觀察者的容器bag
,這是一個集合,當(dāng)信號發(fā)送器發(fā)送事件
之后,所有的觀察者都會得到這個事件,并相應(yīng)的處理。
示意圖如下:
下面是一個例子,演示了信號的基本使用:
我相信在沒有使用過RAS或者類似框架之前,這看起來肯定是一頭霧水。我一步一步來解釋。在解釋之前,我需要先介紹跟信號有關(guān)的幾個類或者結(jié)構(gòu):
Signal
,Event
,Oberser
。
-
首先看看信號
Signal
這個類
這是一個泛型類。包含了兩個泛型 -
Value
、Error
。并且Error
遵循的是Swift中的Error協(xié)議。所以每次我們創(chuàng)建一個Signal對象的時候,我們就必須要附帶將這兩個泛型具體化,在上面的示例中,我將String
和NoError
作為Signal的關(guān)聯(lián)類型。
對于Signal
對象的創(chuàng)建實際上有很多方法,但是每個方法都會使用到一個基本方法:
public init(_ generator: (Observer, Lifetime) -> Void) {
core = Core(generator)
}
基本方法中包含了一個(Observer, Lifetime) -> Void
函數(shù)作為參數(shù),這個函數(shù)中的兩個參數(shù)類型分別是Observer
和Lifetime
。Observer
下面我們會將到,Lifetime
是信號的生命周期類,它將控制信號的銷毀,我們一般不用理會,默認(rèn)情況下,信號將會在生命周期結(jié)束的時候由框架自動銷毀(terminal)。
Core
類是Singal
的核心,它控制信號的創(chuàng)建和銷毀,同時也會給于信號操作的原子性,目前我們只當(dāng)它是一個Singal
的代理,Singal
核心的一些方法都由Core
完成。比如上面的基本方法就是由Core
經(jīng)手創(chuàng)建。Core
在創(chuàng)建的過程中會將獲取到的 generator
函數(shù)實現(xiàn):
core
的初始化函數(shù)中,使用Core本身的一個函數(shù)private func send(_ event: Event){}
創(chuàng)建了一個Oberser
對象,這里創(chuàng)建的實際上就是一個內(nèi)部的發(fā)射器
。我們在調(diào)用Signal
初始化的時候,實際上也就是調(diào)用了core
的初始化函數(shù)。這個函數(shù)會把創(chuàng)建的Oberser
暴露出來,我們使用外部的發(fā)射器引用這個內(nèi)部的發(fā)射器即可。
到這里我們就不得不深入看看 Observer
類了。在看Observer
之前,我們先了解一下事件Event
。
-
Event 枚舉
事件是RAS中最基本的單元。Cocoa中,一個點擊、一個輸入操作、一個動畫甚至是一個網(wǎng)絡(luò)請求事件的完成都是一個事件。RAS中所說的信號發(fā)送,實際上是發(fā)送一個事件產(chǎn)生的后續(xù)影響。
事件在RAS中對應(yīng)的類Event
實際上是一個枚舉。這個枚舉被包含在Signal
之中,所以對于Event
我們并不能直接訪問,而是通過Signal<Value,Error:Swift.Error>. Event
來訪問的。Event
枚舉中包含了四個事件類型:value類型、failed類型、completed類型以及interrrupted類型。
value:值事件,我們可以理解為這事一個有效事件,大部分使用RAS關(guān)注的時候就是這一類型事件的信號,這個枚舉值關(guān)聯(lián)的就是事件的 Value。
failed:錯誤事件,發(fā)送一個帶有錯誤的信號的時候,內(nèi)部包含的就是這樣一個描述錯誤的事件。這個枚舉值關(guān)聯(lián)的就是事件的 錯誤信息ERROR。
completed :完成事件。當(dāng)一次事件信號完成發(fā)送的時候發(fā)出的信號。
interrrupted:中斷事件。未完成中段事件。
我們可以直接創(chuàng)建一個事件:
let eventInt: Signal<NSInteger,NoError>.Event = .value(100)
事件是Observer
們關(guān)注的東西,接下來看看Observer
是怎么觀察事件的。
-
觀察者Observer類
和Event 一樣,Observer
也被包含在Singal之中,所以我們在創(chuàng)建Observer
的時候,需要通過Signal
來訪問。看起來很長:var sendOb: Signal<String,NoError>.Observer?
。
Observer
中包含一個事件的調(diào)用函數(shù),形如:(Event)->(void)
,這個調(diào)用函數(shù)在被創(chuàng)建之后,將會保存在Observer
的一個屬性_send中。很顯然_send函數(shù)包含一個類型為Event
的參數(shù)。創(chuàng)建Oberser
對象的函數(shù)原型:
public typealias Action = (Event) -> Void
public init(_ action: @escaping Action) {
self._send = action
self.wrapped = nil
self.interruptsOnDeinit = false
}
除了這個方法還有一個創(chuàng)建OBerser
對象的方法。但也是基于上面的方法的。
Observer
創(chuàng)建之后,可以通過調(diào)用對象的send()系列方法發(fā)送各種不同類型的事件信號了。
講完這個幾個類,就可以明白我們的示例到底是怎么運(yùn)行的了。
2.示例代碼解讀
1.首先我們看看發(fā)送器sendOb
sendOb是一個 Signal<Value,Error:Swift.Error>.Observer?
類。上面說了,因為這個類被包含在Signal
中。
因此我們沒有辦法直接使用它,而是通過Signal<Value,Error:Swift.Error>.Observer?
( 下用Observer
代替描述)來獲取。在示例中,我申明了一個空的Observer
,這個就是外部的發(fā)射器,目前它為空,沒有任何的作用。
2.接下來創(chuàng)建一個Signal
,根據(jù)上面說的,Signal
在創(chuàng)建的時候,會將其內(nèi)部的發(fā)射器( Oberser
類型)暴露出來,我將之保存在外部的發(fā)射器中。
3.然后創(chuàng)建兩個觀察者。這里比較容易讓人迷惑的是,觀察者的類型也是Oberser
。原因是RAS中,信號不一定是單獨(dú)存在的,它還可以和其他的信號建立聯(lián)系,這時候發(fā)射器
將作為橋接Oberser
,作為其他Signal
的觀察者。回到正題,之前我們說了,Oberser
對象的核心是包含一個(Event)->(void)
的函數(shù),我們在創(chuàng)建兩個觀察者的時候,分別實現(xiàn)了這個函數(shù)。
4.把觀察者和信號關(guān)聯(lián)起來。 這里回到上面的示意圖,所謂的關(guān)聯(lián),實際上是把觀察者對象的引用加入到Signal
對象的bag
中,當(dāng)Signal
的發(fā)射器
發(fā)送事件的時候,會遍歷bag
,調(diào)用 bag
中所有的觀察者的send系列函數(shù)。
5.發(fā)射器發(fā)送事件。發(fā)送事件之后,與信號綁定的觀察者都會收到發(fā)出的事件。
上述方法中,Oberser
發(fā)送器是我們直接創(chuàng)建的,然后引用Signal
內(nèi)部的發(fā)送器,獲取到Signal
,Oberser
兩個對象。 而在Signal
中,還有一個便利構(gòu)造器: pipe()
這個便利構(gòu)造器將返回一個類型為(
Signal
,Oberser
)的元組。我們最終一次獲取到了需要的Signal
,Oberser
兩個對象。