本篇博客我們就來聊一下combineLatest()的使用以及具體的實現方式。在之前的《iOS開發之ReactiveCocoa下的MVVM》的博客中我們已經聊過combineLatest()的用法,雖然是使用老版本的ReactiveCocoa和Objective-C語言介紹的,不過使用原理上都是一致的。都是將兩個信號量進行合並,當其中一個信號量發出Value事件時,如果另一個信號量之前也發送過Value事件,那么就取出最后一個事件的Value值與當前發送的事件值進行合並,然后將合並后的值發送給新的信號量的觀察者。如果其中一個未發送過任何Value,那么將不會向合並后的信號量的觀察者發送事件。下方會進行詳細的敘述。
下面我們就來仔細的聊一下combineLatest()的使用方式、具體的代碼實現以及合並信號量的工作原理。下方的使用示例我們還是與《iOS開發之ReactiveCocoa下的MVVM》這篇博客中聊combineLatest()時使用是示例相同,只不過我們是使用的Swift語言寫的,詳情如下。
一、combineLatest()使用
下方代碼片段是combineLatest()使用方式,介紹如下:
-
首先創建兩個信號量,一個是 signalString,用來發送Value值為String類型的信號。另一個是 signalInt,用來發送Value值為Int類型的信號。
-
調用信號量 signalString的combineLatest()方法,將signalString信號量最后發送的值與信號量 signalInt最后發送的值進行合並。然后將合並后的元組(String, Int)發送給新創建的combineLatestSignal信號量的所有觀察者。
-
接着就是調用 signalString和 signalInt所對應的 observer對象來發送Value事件了。
從輸出結果我們不難看出,無論是signalString信號量還是signalInt信號量發出的Value消息,只要是另一個信號量的LastValue不為nil。那么新的信號量combineSignal的觀察者就會收到相應的合並后的值,如下具體結果如下所示:
針對上述的示例,我們畫了下方的簡圖來說明合並信號量的工作方式。Letters和Number是兩個信號量,Combine是兩者通過combineLatest()方法生成的新的信號量,然后Letters和Number信號量就隨機發送消息。Combine信號量根據Letter和Numbers發送值的情況進行信號量的輸出。具體如下所示。
二、combineLatest()的具體代碼實現
接下來我們就來看一下combineLatest()代碼的具體實現。下方就是該方法對應的核心代碼:
-
首先下方這個泛型函數的參數是一個信號量,而返回值是一個新的信號量,而這個新的信號量的類型是一個可以接受元組的信號量。而這個元組中的兩個值就是這兩個信號量最后一個值合並而成的。
-
其次創建了一個 NSLock類型的鎖,用來保證多線程下的原子性操作。
-
定義聲明兩個常量對象,用來存儲兩個合並信號量最后發送的值。 CombineLatestState<Value>類的實現是比較簡單的,目的就是為了暫存信號量最后發出的值。
-
然后有定義了一個無參閉包 onBothValue, 而這個閉包體中所做的事情是像新生成的合並信號量發送合並后的元組消息。這樣,與新信號量所關聯的觀察者Observer就會收到這個元組。
-
緊接着就是創建了一個新的代理觀察者observerDelegate, 用來代理新信號量的 Observer來發送各種事件。而這個 observerDelegate代理觀察者是代替合並后的新信號量發送事件的。
-
最后要做的就是將 observerDelegate與要合並的兩個信號量進行整合關聯,使得要合並的兩個信號量中的任何一個信號量發出事件時。在兩者都有 LatestValue的情況下,這個新合並的信號量所綁定的觀察者都可以接收到該事件。
具體代碼如下所示:
下方這個方法就負責將新的信號量的發送事件的Observer與之前信號量進行整合。具體做法就是往之前的信號量的Bag容器中添加一個新的觀察者Observer,在這個新的觀察者處理Event事件時,調用ObserverDelegate的相關事件即可。
在上述代碼中,我們對暫存之前兩個信號量最后發出的值的signalState和otherState進行了相關信息的打印。先打印了hashValue,然后打印了其暫存的值。當着兩個對象中的latestValue皆不為空時,那么就調用observerDelegate的sendValue方法執行onBothValue閉包,向合並信號量所有的Observer發送元組消息即可。
下方就是對signalState和otherState的相關信息進行的打印 ,從打印信息中我們可以看出,盡管在observerWithState()函數中是以參數的形式獲取的signalState和otherState,但是其內存地址是不變的,獨一份。而且當這兩個都有lastestValue的情況下,合並信號量的觀察者才會收到相應的Value事件。具體如下所示。
三、Latest合並原理圖
針對上述的代碼實現,以及參考之前博客中原理圖的形式,於是乎我們給出了下方的這個原理圖。原理圖應該是清晰明了,一目了然的,在此就不做過多的贅述了。通過下圖的結構,我們不難看出,combineLatestSignal信號量仍然是可以進行鏈式發展的。
在Signal.swift文件中關於SignalProtocol的擴展的方法中,基本上是按照上述的套路來擴展的。大體就是一個方法返回一個新的信號量,這個新的信號量與原始信號量間通過橋接信號量來進行關聯。不同的方法在處理原信號量往新的信號量發送事件時,在中間所做的事情不同。Signal.swift文件中還有好多類似的方法,在此就不一一進行介紹了,如果你對某個方法的實現感興趣,可以采用上述的套路來進行解析。
今天的博客就先到這兒,下篇博客我們會繼續解析ReactiveSwift框架中的其他內容。
上述代碼github分享地址:https://github.com/lizelu/TipSwiftForRac 。