ReactiveCocoa源碼解析(二)Bag容器的代碼實現

今天博客我接著上篇博客的內容來,上篇博客我們詳細的看了ReactiveSwift中的Observer已經Event的代碼實現。接下來我們來看一下ReactiveSwift中的結構體Bag的實現。Bag:袋子,顧明思議,就是用來裝東西的,我們暫且將Bag稱之為容器。在ReactiveSwift中的Bag主要是用來存儲Signal對象的,我們在後期介紹ReactiveSwift源碼時會陸陸續續的看到Bag的身影。

因為Bag這個結構體在ReactiveSwift中比較獨立,所以我們本篇博客就來聊一下Bag的具體實現。本篇博客我們會詳細的介紹Bag的代碼實現,並從Bag代碼實現中看一下Swift語言本身的東西,並給出Bag的測試用例。當然,本篇博客我們還會涉及到“迭代器模式”,關於“迭代器模式”更詳細的信息,請移步於之前發佈的關於設計模式的博客《設計模式(十):從電影院中認識"迭代器模式"(Iterator Pattern)》。

一、ContiguousArray

在博客的第一部分我們先來看一下ContiguousArray的相關內容。因為結構體Bag就是在ContiguousArray的基礎上進行封裝的,也就是說袋子中的元素最終是存放在ContiguousArray中的。在Swift中ContiguousArray與Array的用法差不多,下方是官方對ContiguousArray的介紹。

從下方我們可以清楚的知道ContiguousArray、Array還有ArraySlice的大部分屬性和方法是共用的。但是在存儲Class或者@objc協議時,使用ContiguousArray效率會更高一些。但是ContiguousArray不能和Objective-C的NSArray進行橋接,並且不能將ContiguousArray傳入到Objective-C的API中。

當然從ContiguousArray名字來看,它是佔用連續存儲空間的數組。具體請看下方的官方介紹。

ReactiveCocoa源碼解析(二)Bag容器的代碼實現

二、Bag的基本實現

下方是結構體Bag的基本實現,稍後還會介紹Bag的延展以及與其關聯的BagElement類型。接下來我們來詳細的看一下其實現。當然下方截圖中的代碼實現,是將ReactiveSwift中的英文註釋給刪了,添加了一些中文註釋。這樣看著更舒服一些。

1、RemovalToken

首先我們來看一下RemovalToken,以及看一下RemovalToken這個類在Bag結構體中所扮演的角色。從下方代碼片段中我們不難看出,RemovalToken是一個空類,中該類的名字我們可以看出,該類的對象是充當Token用的。也就是說該類的對象可以作為Bag中所存儲元素的唯一標示符,並且可以用來刪除元素使用。

我們知道,每個類的對象都會有一個唯一的HashValue。其實在Bag中真正使用到的是RemovalToken的對象所對應的HashValue,這個稍後我們會聊到。

2.Bag的基本實現

從下方代碼段中,我們可以看出Bag是以結構體的形式存在的,而且後邊緊跟了一個Element的泛型類型。緊接著是類型為ContiguousArray<BagElement<Element>>的泛型數組,BagElement<Element>這個類型稍後會提到。

insert方法負責插入元素,從代碼實現來看其實就是向elements數組後方append元素,添加的元素類型為BagElement。inser方法由@discardableResult進行修飾,說明insert方法所返回的值可以被忽略,也就是說如果沒有變量來接收insert的返回值的話,程序並不會報出警告。而insert前方的mutating關鍵字一般用來修飾Swift中的枚舉或者結構體中的方法,被mutating關鍵字修飾的方法就可以修改枚舉或者結構體中的屬性了。用法如下所示。

接下來我們來看一下remove方法,該方法的參數是一個token,其功能就是通過token來刪除元素。當然具體代碼實現也是比較簡單的,就是對elements數組進行遍歷,找到元素的token與傳入的token一致的話,我們就將其刪除。具體實現如下所示。

ReactiveCocoa源碼解析(二)Bag容器的代碼實現

三、BagElement結構體的實現

接下來,我們來看一下Bag中所存儲元素的類型BagElement的實現,代碼如下所示。當然實現比較簡單,BagElement也是一個泛型結構體,其泛型類型Value其實就是Bag的泛型類型Element。其中有兩個屬性,一個Value,用來存儲值。另一個是token,用來存儲該值對應的唯一標示。

緊接著是BagElement的的延展,用來輸出描述信息的,如下所示。

ReactiveCocoa源碼解析(二)Bag容器的代碼實現

四、Bag的延展

接下來我們來看一下Bag的延展,代碼如下所示。Bag的延展中的相關內容還是比較簡單的。首先定義了一個Array<Element>.Index的類型別名Index,其實就是Int類型。然後是startIndex和endIndex兩個計算屬性,用來獲取Bag的第一個元素的索引,和結束位置的索引。

subscript方法是為Bag結構體添加自定義下標,使其支持下標訪問元素的形式。makeIterator方法則用來創建Bag<Element>所對應的迭代器。關於Bag的迭代器,稍後會進行介紹。

ReactiveCocoa源碼解析(二)Bag容器的代碼實現

五、Bag的迭代器

接下來我我們就來看一下Bag容器的迭代器,其實就是“迭代器模式”的具體應用。下方代碼段就是Bag的迭代器的具體實現。從下方代碼我們不難看出,BagIterator實現了Swift中的迭代器協議IteratorProtocol,然後給出了迭代器的next方法的實現。下方我們將會對該迭代器進行測試。

ReactiveCocoa源碼解析(二)Bag容器的代碼實現

六、Bag的測試用例

下方代碼片段中是對Bag的測試用例。首先我們初始化了一個Bag實例,然後指定其泛型類型為String。緊接著我們又創建了一個bagsTokens的數組,用來存儲myBags中每個元素所對應的token,便於在移除元素時使用。最後是往myBags中添加值了。每添加一個值我們就記錄一下該值所對應的token。

在添加完元素後,我們可以遍歷輸出一下每個token對象的HashValue。然後我們可以通過token來移除myBags中的元素。

最後我們可以從myBags中獲取相應的迭代器,然後使用迭代器訪問myBags中的元素。

ReactiveCocoa源碼解析(二)Bag容器的代碼實現

下方是對Bag中的Token以及Bag中的所有元素進行的輸出,如下所示:

ReactiveCocoa源碼解析(二)Bag容器的代碼實現

今天博客就先到這兒,下篇博客會繼續更新ReactiveSwift相關的東西。

相關推薦

推薦中...