ReactiveSwift源碼解析(六) SignalProtocol的take(first)與collect()延展實現

上篇博客咱們聊了observe()、map()、filter()延展函數的具體實現方式以及使用方式。咱們在以前的博客中已經聊過,Signal的主要功能是位於SignalProtocol的協議延展中的,並且延展函數是很是的多的。今天博客中咱們繼續來聊SignalProtocol中那些比較核心的延展實現。本篇博客咱們就來聊一下take()函數的使用以及實現方式,而且再聊一下Signal中collect()的相關實現。git

 

1、take(first)github

本部分咱們就來聊一下take(first)的使用方式以及具體的實現方式。與上篇博客的套路相似,咱們聊完代碼後,依然會給出take(first)函數的運做方式。若是你看過上篇博客的內容的話,那麼take(first)方法是比較好理解的。由於take(first)也是能夠鏈式發展的,而且使用時的總體結構與map()filter()方法差很少,只不事後二者接收的是一個閉包,而take(first)方法接收的是一個值罷了。api

一、take(first)方法的使用數組

下方示例是ReactiveSwift官方給出的take(first)的使用示例,對其解釋以下:閉包

  • 首先仍是經過 pipe()函數來建立一個 signal信號量,並獲的其內置的 observer
  • 而後經過調用signal的 take(first)方法來建立一個新的信號量 takeSignal。在調用 take(first)時,傳入的參數是3.
  • 接着建立一個觀察者 subscriber,並給出該觀察者在收到Value事件的處理閉包。
  • 最後就是調用 signal內置的 observer來發送 Value事件了。

從下方代碼片斷的輸出結果咱們不難看出,發出的4個Value事件中只有前三個事件會被takeSignal的觀察者收到。而其餘的takeSignal的觀察者是收不到的。從這一點咱們就能明確的看出take(first)函數錯建立的信號量的功能。take()的參數若是是N的話,那麼就表示,take()所返回的信號量只能接受原信號量所發送事件的前N個。app

  

 

二、take(first)方法的具體實現框架

看完take(first)方法的使用方式,接下來咱們就來看一下take(first)的具體代碼實現。下方的SignalProtocol的延展就是take(first)方法的實現,解釋以下:函數

  • take()方法也會返回一個新的Signal對象,也是能夠鏈式發展的,不過在建立Signal對象時添加了一些條件判斷。
  • 首先必須保證 count爲非負數的值。
  • 而後當count爲0時,直接執行新信號量中 observersendCompleted()方法,結束事件的接收。
  • count > 0時,就建立一個take計數變量來記錄接收Value事件的次數,若是 take == count時,說明接收事件的次數已達到上限。就調用 sendCompleted()方法,結束新返回信號量的觀察者接收消息。

  

 

三、執行原理圖spa

take()函數的執行過程與map()filter()函數差很少,都是能夠鏈式發展的。新建立的Signal對象與以前對象間都會有一個橋接觀察者。這幾個函數間的不一樣就在於這個橋接觀察者在發送消息所遵循的條件不一樣。下方就是該執行原理圖:server

 

 

2、Collection的使用

接下來咱們來看一下接收集合類型的信號量。Signal的collect()相關的方法會生成一個新的信號量,而該信號量能夠接受以前信號量的集合。也就是說信號量的值是成批發送的。本部分咱們就來聊聊信號量中的集合的使用方式以及具體的代碼實現方式。下方是collec相關的延展方法的使用示例。

接下來咱們就來一一列舉一下集合信號量的使用方式,在ReactiveSwift中,主要有4中集合信號量的使用方式,下面將會一一列舉。

一、collect()

下方代碼片斷就是collect()方法的使用示例,解釋以下:

  • 首先調用signal對象的 collect()方法生成一個新的信號量 collectionSignal
  • 而後給這個集合信號量 collectionSignal關聯一個觀察者 subscriber
  • 而後調用原來signal的 observer來連續的發送信號量,信號量的值分別爲一、二、三、4。最後調用一下 sendCompleted()方法表示信號量發送完畢。
  • 最後咱們能夠看到, collectionSignal的觀察者會以集合的形式接收到了上述發送的信號量的值,以下所示。

  

 

二、collect(count)

collect(count)該方法比上述方法多了一個count參數,該參數表示集合可容納元素的最大值,當接收消息的個數爲count時,那麼就將該集合進行輸出,並開始下一個集合的積累。下方就是collect(count)的使用方式。

從下方代碼片斷的輸出結果中咱們能夠看到,輸出結果是兩個集合,由於集合元素個數的最大值咱們設置的爲3。因此每一個集合最可能是3個值。 

  

 

三、collect(_ predicate: @escaping (_ values: [Value]) -> Bool)

該方法接收的是一個條件閉包參數,也就是說predictcate是一個返回Bool類型的條件閉包,閉包中的內容由調用者來提供。該方法能夠根據該條件閉包的結果來判斷是否將已經收到的信號量的值進行打包發送。下方打包發送的條件是集合中的值的和剛好等於8時纔會發送。

  

 

四、collect(_ predicate: @escaping (_ values: [Value], _ value: Value) -> Bool)

該函數與上述仍是相似,也是接收一個條件閉包,只不過給條件閉包的參數除了當前集合內的元素數組外,還有一個當前接收但還沒有入集合的信號量的值。咱們能夠根據這兩個參數作一些判斷,而後在決定是否進行結合信號量的發送。

下方代碼片斷的意思是若是當前發送的值爲7,那麼就將以前的集合進行發送,發送後並清空,而後將當前爲7的值加入到清空後的集合中。下方是調用方式以及輸出結果。

  

 

 

3、Collection相關信號量的實現方式

上面咱們看完了collect()及其相關方式的使用示例,接下來我咱們就來看之前其內部具體的代碼實現了。本部分就來看一下相關的代碼實現細節。 

一、CollectState<Value>的實現

首先咱們先來看一下CollectState的實現。CollectState就是二次封裝的數組集合,封裝後更適合咱們集合信號量進行元素的存儲和清空。也就是說,集合信號量所接收的信號量的值,是暫存在CollectState這個泛型集合中的。下方就是CollectState<Value>的實現方式。

該代碼比較簡單就是對數組進行的二次封裝,其中的append(value)方法就負責往數組中添加元素,而flush()方法則負責將數組進行清空。isEmpty計算屬性則用來判斷values數組是否爲空。

  

 

二、collect(_ predicate: @escaping (_ values: [Value]) -> Bool)方法的實現

接下來咱們就來看一下collect(_ predicate: @escaping (_ values: [Value]) -> Bool)方法的實現,該方法中的總體結構與take()以及以前聊的map()、filter()函數類似,都是返回一個新的信號量,而且將這個新的信號量的Observer與以前信號量Bag中的一個Observer對象的事件進行關聯。對下方代碼片斷的解釋以下:

  • 首先在建立新的信號量的構造器尾隨閉包中建立了一個類型爲 CollectState<Value>的state,該state集合主要用來暫存原始信號量發送過來的值value。而這個新的信號量的類型爲 Signal<[Value], Error>類型,也就是說這個新建立的信號量發送的值是一個集合類型。
  • 而後在處理以前信號量發送事件時,將取出來的值 append()到state集合中,而後判斷 predicate()閉包條件的值,若是 predicate()條件成立,則集合信號量向其觀察者發送state集合,發送後並清除掉 state中的元素的值。
  • 當接收到原信號量的 sendCompleted()事件時,集合信號量先將stata中的元素髮送出去,而後調用其自己的 sendCompleted()結束信號量的發送。

  

 

三、collect(_ predicate: @escaping (_ values: [Value], _ value: Value) -> Bool)

該方法的實現與上述方法的實現極爲相識,只不過是閉包條件所攜帶的參數不一樣,而且處理條件的方式也不一樣。由下方代碼咱們不難看出,當條件閉包成立時,集合信號量進行事件發送,而後將state集合進行狀況,而後在將當前的值添加到已經被清空的state集合中。

也就是說,當條件成立時所發送的集合中是不包括當前所接收到的來着原始信號量的值的。具體以下所示:

  

 

四、collect()和collect(count)的實現

這兩個方式的實現就比較簡單主要是調用上述方法,給上述方法的條件閉包傳入不一樣的值。因實現方法比較簡單,在此就不作過多贅述了。

  

 

4、collect()工做原理圖

上面聊完collect()的具體工做實現,咱們再來看一下collect()的工做原理圖,由於其代碼實現與map()、filter()、take()等方法相似,因此原理圖也差很少。下方就是collect()的工做原理圖。

從下方的工做原理圖咱們清楚的能夠看到,原信號量Signal發送的是value, collectSignal收到這個value值後,將其暫存到[value]集合中,當predicate()閉包的條件成立時,會調用collectSignal的obser的send(value)方法,將集合[value]發送給collectSignal的觀察者。以下所示:

  

今天的博客就先到這兒,下篇博客咱們會繼續解析ReactiveSwift框架中的其餘內容。

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

相關文章
相關標籤/搜索