1. 程式人生 > >ReactiveSwift原始碼解析(八) SignalProducer的程式碼的基本實現

ReactiveSwift原始碼解析(八) SignalProducer的程式碼的基本實現

在前面幾篇部落格中我們詳細的聊了ReactiveSwift中的Bag、Event、Observer以及Signal的使用方式和程式碼實現。那麼在接下來的這幾篇部落格中,我們就依附於之前部落格的基礎上來聊一聊SignalProducer的用法以及內部的程式碼實現。從SignalProducer的名字中,我們容易知道,SignalProducer是訊號量的生產者,確切的說,SignalProducer基於Signal的又一層封裝。擴充了Signal的使用方式,使其更貼近於一些業務場景,比如網路的請求等。

接下來我們看一下SignalProducer的基本實現,也就是看一下SignalProducer

一些核心的構造器和核心的方法。並且給出這些構造器以及核心方法的程式碼解釋並給出其對應的使用方式。

一、SignalProducer的核心屬性、方法和構造器

開門見山,在本篇部落格的第一部分我們先給出SignalProducer結構體的核心屬性、構造器和方法。下方會對這些SignalProducer的核心內容進行介紹,然後再看一下其具體的使用和執行方式。之所以說本部分所介紹的內容是SignalProducer的核心,因為SignalProducer的其他方法、構造器是在下方所要介紹的內容的基礎上所建立起來的。

1、startHandler屬性、init(startHandler)構造器以及startWithSignal()的方法實現

startHandler屬性是SignalProducer結構體的基本實現中的唯一屬性。從下方程式碼片段中我們可以看出startHandler的型別是一個閉包型別。該閉包型別的的引數是ObserverDisposable型別的物件,返回值為空。

而緊接著下方的init(startHandler)構造器就是為startHandler屬性賦值的。雖然該init(startHandler)構造方法簡單,但是是SignalProducer結構體的核心,因為在SignalProducer其他構造器中直接或者間接呼叫了下方的構造方法,稍後我們會給出相應的程式碼實現。 

  

上述程式碼片段中的startWithSignal(setup)

方法,也是SignalProducer結構體中比較核心的方法。因為在SignalProducer結構體的擴充套件方法中直接或者間接的呼叫了該方法。該方法中做的事情比較單一,就是呼叫Signal的pipe()方法建立了一個signal物件與該物件所對應的observer物件。該方法的引數是一個名為setup的閉包,將建立的signal物件交給setup()閉包,將observer物件交給startHandler()閉包。而startHandler的閉包體就是init(startHandler)構造器的尾隨閉包。

2、上述屬性和方法的使用

上述的屬性和方法之所以是SignalProducer結構體的核心,是因為SignalProducer的其他構造器以及擴充套件方法都是在此基數上構建起來的,稍後我們會介紹到。現在我們來看一下上述方法的呼叫方式。下方就是我們給出的針對上述方法的示例和輸出結果。

  • 首先呼叫了SignalProducer的init(startHandler)構造器,建立了一個producer常量。在該構造器的尾隨閉包中,我們可以通過閉包回撥的形式獲取到producer中signal物件所對應的observer,我們可以通過該物件傳送一些值,如下所示。
  • 然後我們建立了一個Observer類的subscribe1物件,並給出了該觀察者的Value事件的處理閉包。
  • 最後我們呼叫startWithSignal啟動producer的訊號量,通過startWithSignal()方法的尾隨閉包,我們可以獲取到producer中的signal物件,然後將我們建立的subscriber觀察者與該signal進行關聯。關聯後,subscriber或收到producer中的observer物件所傳送的Value事件。

最下方就是該段程式碼的執行結果,如下所示。

  

二、SignalProducer中的其他構造器

上面我們聊了SignalProducer的核心構造器,在SignalProducer結構體的構造器陣營中,其構造器都是在上述核心構造器的基礎上衍生出來的快捷構造器。這些衍生出來的構造器適用於特定場景下的SignalProducer的初始化,其功能更為專一,使用更為便捷。接下來我們就來介紹一下這些衍生構造器的程式碼實現以及使用方式。

1、init(signal)和init(value)

下方程式碼片段就是init(signal)和init(value)的具體實現,從下方程式碼片段中我們容易看出,最終都是呼叫的上述我們介紹的init(startHandler)這個構造器。只不過在startHandler這個閉包塊中所做的事情不同罷了。

  

我們先來看init(signal),該構造器接收一個signal訊號量,然後將producer中的observer物件新增為該引數signal訊號量的觀察者,也就是說當這個訊號量傳送訊息是,producer中的observer會收到這個外部訊號量發過來的訊息,然後通知producer中內部的訊號量的所有觀察者。針對上述程式碼實現我們可以畫出下方的簡圖。左邊的mySignal就是通過init(signal)構造器傳過來的訊號量物件,mySignal訊號量中的Bag中儲存了一些該訊號量的觀察者。然後呼叫SignalProducerinit(signal)方法將mySignal訊號量傳給SignalProducer,然後將SignalProducer中的內部訊號量signal所對應的observe新增到mySignalBag中,使其成為mySignal訊號量的觀察者。具體如下所示,稍後我們會給出具體使用方式。

  

上述init(value)構造器就簡單的多了,就是在呼叫init(startHandler)構造器的尾隨閉包中呼叫SignalProducer內部的observer將init(value)提供的引數傳送出去。傳送完畢後就呼叫Observer的sendCompleted()方法,完成訊號量的傳送。

接下來我們來看一下上述兩個構造器的使用示例以及示例的執行結果。

  • 首先我們來看一下init(signal)的使用示例。首先建立了一個mySignal訊號量以及該訊號所對應的myObserver。然後呼叫init(signal)構造器,並把mySignal物件傳給該構造器。接著通過startWithSignal()方法往producer中的signal中新增一個名為subscriber1觀察者。然後呼叫myObserver傳送Value訊號量,我們能看到,producer中訊號量的觀察者subscriber1也能收到該訊號量。
  • init(value)構造器的使用就簡單許多,直接在SignalProducer建立時,將SignalProducer所對應的訊號量所需要傳送的值傳進去即可,如下所示。

  

2、init(action)、init(error)以及init(result)構造器

接下來我們再來看一下這init(action)、init(error)以及init(result)三個構造器,這個三個構造器也是直接或者間接的呼叫了我們之前的核心構造器init(startHandler)。下方就是這三個構造器的具體程式碼實現:

  • init(action)構造器接收了一個名為action的無參閉包,該閉包的返回值為Value。從其程式碼實現我們不難看出,下方程式碼就等同於self.init(value: action())。action閉包的作用就是為observer.send(value)提供值的。
  • init(error)構造器中就是在呼叫init(startHandler)時,在其尾隨閉包中的獲取到observer然後呼叫send(error)方法,傳送Failure事件。
  • init(result)構造器接收的是一個Result列舉物件,目的就是將Result列舉中的success轉換成Value事件,將failure結果轉換成failure事件併發送相應的Error。

因為該三個構造方法比較簡單,就不提供相應的使用示例了,如果你感興趣,可以在官方提供的Playground中進行示例的編寫。

  

3、init(values)和init(first, second, tail…)構造器

本小節我們就來聊一下init(values)和init(first, second, tail)這兩個構造器,這兩個構造器的功能其實差不多,實現方式也是相同的,只不過是呼叫方式不同。下方是這兩個構造器具體的程式碼實現。

  • init(values)構造器接收的是一個可遍歷的序列,在具體的程式碼實現中,我們遍歷該序列,取出其中的每個值,然後呼叫observer的send(value)方法將該值進行傳送。遍歷完成後,呼叫了sendCompleted()方法完成訊號量的傳送。
  • init(first, second, tail ...)構造器是一個不定參構造器。在該構造器中,我們將收到的引數組合成陣列,然後呼叫init(values)構造器,具體實現如下。

  

針對上述的構造器,我們給出了下方這兩個使用示例,以及相應示例的輸出結果。

  

今天的部落格就先到這兒,下篇部落格我們會繼續解析ReactiveSwift框架中的其他內容。