上篇博客我們對Signal的基本實(shí)現(xiàn)以及Signal的面向協(xié)議擴(kuò)展進(jìn)行了介紹, 詳細(xì)內(nèi)容請移步于《Signal中的靜態(tài)屬性靜態(tài)方法以及面向協(xié)議擴(kuò)展》。并且聊了Signal的所有的g功能擴(kuò)展都是放在Signal所實(shí)現(xiàn)的SignalProtocol協(xié)議的擴(kuò)展中的。本篇博客就沿襲上篇博客的內(nèi)容,我們來聊一下SignalProtocol的部分?jǐn)U展。本篇博客我們主要來聊一下對Signal添加Observer的observe()方法擴(kuò)展的具體實(shí)現(xiàn),并且聊一下Signal的MapFilter相關(guān)的功能擴(kuò)展的具體實(shí)現(xiàn)。

當(dāng)然我們在聊相關(guān)源碼的具體實(shí)現(xiàn)時(shí),會給出相關(guān)的測試用例,然后再根據(jù)測試用例來理解其代碼實(shí)現(xiàn)。

 

一、observe()方法的擴(kuò)展

首先我們來看一下observe()方法的擴(kuò)展。通過前幾篇博客的介紹,我們知道SiganlObserver之間的關(guān)聯(lián)是通過observe()方法來實(shí)現(xiàn)的。而observe()方法的核心實(shí)現(xiàn)在上篇博客中已經(jīng)進(jìn)行了詳細(xì)介紹。而在協(xié)議擴(kuò)展中又對observe()方法進(jìn)行了一些擴(kuò)展,這些擴(kuò)展主要是針對一些特定功能為observe()的使用方式添加快捷調(diào)用方式。

1、observe()方法擴(kuò)展的具體實(shí)現(xiàn)

下方個(gè)SignalProtocol的延展主要是對observe()方法的擴(kuò)展,在每個(gè)擴(kuò)展方法中最后還是得調(diào)用Signal類中所實(shí)現(xiàn)的observe()方法。還是那句話,下方的這些observe()方法的擴(kuò)展主要還是Signal類中observe()方法的快捷方式。下方將對observe()的每個(gè)快捷方法進(jìn)行介紹。

  • observe(action) : 該方法傳入的是一個(gè)Action閉包,該Action閉包其實(shí)就是Observer類中的Action閉包。也就是在調(diào)用observe(action)方法時(shí),為Observer的Action提供了閉包體。而在observe(action)方法中要做的就是實(shí)例化Observer對象,并將該對象傳給Signal的observe()方法。稍后會給出該擴(kuò)展方法的使用過程。
  • observeResult(result):該擴(kuò)展方法是將Observer的value事件和failed事件分別轉(zhuǎn)換成Result枚舉的success和failure。
  • observeCompleted(completed): 該擴(kuò)展方法所接收的閉包就是Observer接收completed事件所執(zhí)行的閉包。
  • observeFailed(failed): 該擴(kuò)展方法所接收的閉包就是Observer接收failed事件所執(zhí)行的閉包。
  • observeInterrupted(interrupted): 該擴(kuò)展方法所接收的閉包就是Observer接收interrupted事件所執(zhí)行的閉包。

從下方代碼片段中我們不難看出,都是在Signal的observe()方法的基礎(chǔ)上做的擴(kuò)展,本質(zhì)上就是observe()方法的特定使用的快捷方式。

  萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

 

2、上述擴(kuò)展的使用方式

看完實(shí)現(xiàn),在看上述方法的使用方式就簡單多了。下方代碼片段就是上述擴(kuò)展中每個(gè)方法的使用方式。我們可以根據(jù)具體的業(yè)務(wù)場景以及具體的功能來選擇實(shí)現(xiàn)那種方法來滿足自己的開發(fā)需求。從下方每個(gè)方法中的調(diào)用方式可以看出,每個(gè)方法在調(diào)用時(shí)所提供的尾隨閉包就是該方法所表示的快捷方式。

當(dāng)然,下方所有的方法,我們都可以使用Signal中的observe()方法來實(shí)現(xiàn),只不過沒有下方這些方法方便快捷。

  萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

 

 

 

二、SignalProtocol的Map擴(kuò)展

在《ReactiveSwift源碼解析之Event與Observer》這篇博客中我們聊了Event的Map函數(shù),主要是將一個(gè)類型的Event(如Event<Value, Error>)轉(zhuǎn)換成另一個(gè)Event類型(如Event<U, Error>)。Signal的Map函數(shù)也不例外,也是將一個(gè)類型的Signal轉(zhuǎn)換成另一個(gè)類型的Signal。當(dāng)然,Signal的Map函數(shù)本質(zhì)上還是使用了Event的Map函數(shù)。

根據(jù)之前對ReactiveSwift框架的解析,我們不難發(fā)現(xiàn)Signal、Observer以及Event三者要想進(jìn)行溝通是其泛型類型必須是相同的,也就是一套的。Map函數(shù)就是為了解決Signal類型與Observer的類型不匹配而生的。也就是說我們可以通過Map函數(shù)的處理,一個(gè)Int類型的Signal可以發(fā)送給String類型的Observer的,如果沒有Map函數(shù)的支持,是做不到這一點(diǎn)的。

可以說Map函數(shù)是“適配器模式”的一種應(yīng)用方式??梢詫⒉煌愋偷男盘柫亢陀^察者進(jìn)行適配使其正常通信。接下來我們就來看一下SignalProtocol協(xié)議的Map相關(guān)的擴(kuò)展以及使用方式。

 

1、map<U>() -> Signal<U, Error> 映射函數(shù)

map<U>()就是擴(kuò)展中的Map相關(guān)函數(shù)之一。該函數(shù)是一個(gè)泛型函數(shù),其返還值是一個(gè)Signal<U, Error>類型的對象。也就是說,一個(gè)Signal<Value, Error>類型的信號量可以通過map<U>()函數(shù)映射成一個(gè)Signal<U, Error>類型的信號量。當(dāng)然map<U>()函數(shù)的參數(shù)是一個(gè)尾隨閉包,該閉包有map函數(shù)的調(diào)用者提供,目的就是為了讓用戶自定義兩個(gè)信號量之間的映射規(guī)則。

首先我們來看一下map函數(shù)的使用方式,下方代碼片段中是map函數(shù)的使用示例以及輸出結(jié)果,下方是對這段代碼的解釋:

  • 首先我們通過Signal的pipe()靜態(tài)方法創(chuàng)建了一個(gè)類型為Signal<Int, NoError>的信號量signal。
  • 然后通過signal的map函數(shù)創(chuàng)建了一個(gè)新的類型為Signal<String, NoError>的信號量mappedSignal。map函數(shù)的尾隨閉包中就是映射規(guī)則,其中value是Int類型,而返回值是String類型。
  • 然后創(chuàng)建了一個(gè)Observer<String, NoError>類型的觀察者subscriber, 并將subscribermappedSignal進(jìn)行關(guān)聯(lián)
  • 最后我們調(diào)用signalobserver對象發(fā)送value事件,該事件所攜帶的值為整數(shù)10。由輸出結(jié)果我們可以知道,與mappedSignal關(guān)聯(lián)的觀察者subscriber盡管只接收String類型的事件,但是經(jīng)過map函數(shù)的處理此刻也是可以收到來自signal的整數(shù)值信號量的。

  萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

 

看完map函數(shù)的用法后我們來看一下其具體的代碼實(shí)現(xiàn)。下方就是上述示例所調(diào)用的map()函數(shù)的具體實(shí)現(xiàn)代碼。在map()函數(shù)中返回了一個(gè)類型為Signal<U, Error>的信號量對象。在Signal的構(gòu)造器的尾隨閉包中又調(diào)用了observe(action)方法將新創(chuàng)建的Signal的observer對象所對應(yīng)的action添加到了之前Signal對象中。

  萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

 

上述代碼的執(zhí)行過程也許有些繞,我們可以通過一張簡圖來看一下上述代碼的執(zhí)行過程。下方是對該過程進(jìn)一步的解釋:

  • 首先類型為Signal<Value, Error>的signal對象調(diào)用其map<U>()函數(shù)生成了一個(gè)新的類型為Signal<U, Error>的newSignal對象。
  • 然后通過Event的map<U>()函數(shù),將signal對象中類型為Event<Value, Error>的事件通過調(diào)用事件的map<U>()函數(shù)將其映射成類型為Event<U, Error>的newEvent事件對象。
  • 然后我們將新的newEvent添加到newSignalobserveraction中。
  • 然后使用newSignalobserver的action創(chuàng)建一個(gè)類型為Observer<Value, Error>的newObserver對象。
  • 最后將這個(gè)新的newObserver對象添加到舊的signalBag中。

  萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

上述是代碼的調(diào)用步驟,我們可以看一下具體的執(zhí)行過程,如下圖所示。從下圖的結(jié)構(gòu)我們不難看出map()函數(shù)是鏈?zhǔn)桨l(fā)展的,下發(fā)的mappedSignal還可以調(diào)用其自己的map()函數(shù)來生成新的Signal對象。在這個(gè)鏈上的所有Observer都會接受到最原始的Signal對象所發(fā)出的事件消息。signal與mappedSignal橋接的最終手段還是Event的map()函數(shù)。

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

 

2、mapError<F>() -> Signal<U, F> 映射函數(shù)

mapError<F>()映射函數(shù)的實(shí)現(xiàn)機(jī)制和使用方式與上述的映射函數(shù)即為相似。只不過該映射函數(shù)使用了Event的mapError<F>()函數(shù)。因該映射還是的實(shí)現(xiàn)方式與上述函數(shù)類似,在此就不做過多贅述了。

關(guān)于lazyMap<U>()的實(shí)現(xiàn)和使用方式,我們暫且不說,后邊聊到SignalProducer以及Flatten時(shí)我們再做補(bǔ)充。

 

 

三、SignalProtocol的filter擴(kuò)展

Filter顧明思議,就是用來過濾東西的。如果你理解上述map的工作原理的話,F(xiàn)ilter就顯得簡單多了。Filter的工作原理以及實(shí)現(xiàn)方式與map相似,只不過將Event的map改成了過濾條件。首先我們將會給出Filter的使用方式,然后在該處Filter的代碼實(shí)現(xiàn)方式并給出工作原理圖。

1、Filter的使用方式

關(guān)于Filter的使用,我們就使用ReactiveSwift官方的示例,下方是對該示例的解釋:

  • 首先使用pipe創(chuàng)建一個(gè)signal,然后獲取到該signal發(fā)送消息的句柄observer。
  • 然后通過調(diào)用signal的filter()函數(shù)來獲取過濾信號量filteredSignal,filter()函數(shù)的尾隨閉包中跟著的是過濾條件。
  • 然后往filteredSignal信號量中添加觀察者subscriber。
  • 當(dāng)使用signal信號量發(fā)送事件時(shí),符合過濾條件的事件才會被過濾信號量filteredSignal所關(guān)聯(lián)的觀察者接收

下方截圖中我們的過濾條件是事件綁定的值必須大于12,也就大于12的Value事件才會被觀察者接受,所以輸出的結(jié)果只有13和14兩個(gè),具體如下所示。

  萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

 

2、Filter的代碼實(shí)現(xiàn)

看完Filter的使用方式,接下來我們來看一下Filter的代碼實(shí)現(xiàn)方式。下方代碼片段就是filter函數(shù)的具體實(shí)現(xiàn),從代碼結(jié)構(gòu)上來看,與上述的map函數(shù)差不多,都是返回一個(gè)新的Signal對象,新的Signal對象與原來的Signal對象之間有一個(gè)橋接觀察者來進(jìn)行通信的。self.observer()函數(shù)后邊的閉包就是橋接觀察者從原信號量中發(fā)出的事件,然后在該事件中根據(jù)過濾條件來判斷是否向新的信號量所綁定的所有觀察者轉(zhuǎn)發(fā)該事件。

從下方代碼中我們明確的可以看出,當(dāng)條件閉包predicate()的值為true時(shí),observer就會對值的事件進(jìn)行轉(zhuǎn)發(fā),然后過濾信號量所綁定的觀察者就可以收到這些事件了。

  萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

 

3、執(zhí)行原理圖

下方就是filter的執(zhí)行原理圖,該圖的結(jié)構(gòu)與map()函數(shù)的執(zhí)行結(jié)構(gòu)類似。從下方圖中我們不難看出,filter()函數(shù)也是支持鏈?zhǔn)桨l(fā)展的,就是可以在新的filterSignal的對象上我們?nèi)稳豢梢蕴砑有碌倪^濾條件條件。因?yàn)闊o論是map()還是filter()函數(shù)都會返回一個(gè)新的Signal對象,并且兩者都是可以鏈?zhǔn)桨l(fā)展的,所以我們可以這樣去寫signal.map().filter().map().filter().filter()……

萬碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

 

在filter下方還有一個(gè)filterMap<U>()函數(shù),該函數(shù)的主要功能是用來Map的,代碼實(shí)現(xiàn)方式與與上述的filter類似,只不過是map的功能,但是該map功能有過濾功能,可以過濾掉nil的值。擴(kuò)展中的skipNil()方法中調(diào)用的就是filterMap<U>()函數(shù),在此就不做過多贅述了。

 

今天的博客就先到這兒,下篇博客我們會繼續(xù)解析ReactiveSwift框架中的其他內(nèi)容。

上述代碼github分享地址:https://github.com/lizelu/TipSwiftForRac 

 

作者:青玉伏案 
出處:http://www.cnblogs.com/ludashi/ 
本文版權(quán)歸作者和共博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。 
如果文中有什么錯(cuò)誤,歡迎指出。以免更多的人被誤導(dǎo)。

http://www.cnblogs.com/ludashi/p/6963233.html