ReactiveCocoa - Swift 解讀系列一:信號的創(chuàng)建以及發(fā)送事件

最近花了一點時間去學(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)的處理。

示意圖如下:


信號內(nèi)部

下面是一個例子,演示了信號的基本使用:


信號創(chuàng)建和使用

運(yùn)行打印

我相信在沒有使用過RAS或者類似框架之前,這看起來肯定是一頭霧水。我一步一步來解釋。在解釋之前,我需要先介紹跟信號有關(guān)的幾個類或者結(jié)構(gòu):Signal,Event,Oberser

  • 首先看看信號Signal這個類

Signal

這是一個泛型類。包含了兩個泛型 - ValueError。并且Error遵循的是Swift中的Error協(xié)議。所以每次我們創(chuàng)建一個Signal對象的時候,我們就必須要附帶將這兩個泛型具體化,在上面的示例中,我將StringNoError作為Signal的關(guān)聯(lián)類型。

對于Signal對象的創(chuàng)建實際上有很多方法,但是每個方法都會使用到一個基本方法:

    public init(_ generator: (Observer, Lifetime) -> Void) {
        core = Core(generator)
    }

基本方法中包含了一個(Observer, Lifetime) -> Void函數(shù)作為參數(shù),這個函數(shù)中的兩個參數(shù)類型分別是ObserverLifetimeObserver下面我們會將到,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實現(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類型。

Event

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?

class 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ā)送各種不同類型的事件信號了。

Observer的發(fā)送函數(shù)

講完這個幾個類,就可以明白我們的示例到底是怎么運(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()

pipe便利構(gòu)造器

這個便利構(gòu)造器將返回一個類型為(SignalOberser)的元組。我們最終一次獲取到了需要的Signal,Oberser兩個對象。

以上就是RAS中信號從創(chuàng)建(設(shè)定發(fā)射器,綁定觀察者)到發(fā)送信息的全部流程了。 當(dāng)然信號還有其他更多的可操作事務(wù),這篇文章就暫時寫到這里。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內(nèi)容