1. 程式人生 > >ReactiveSwift原始碼解析(二) Bag容器的程式碼實現

ReactiveSwift原始碼解析(二) Bag容器的程式碼實現

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

因為Bag這個結構體在ReactiveSwift中比較獨立,所以我們本篇部落格就來聊一下Bag的具體實現。本篇部落格我們會詳細的介紹Bag的程式碼實現,並從Bag程式碼實現中看一下Swift語言本身的東西,並給出Bag的測試用例。當然,本篇部落格我們還會涉及到“迭代器模式”,關於“迭代器模式”更詳細的資訊,請移步於之前釋出的關於設計模式的部落格《》。

一、ContiguousArray

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

從下方我們可以清楚的知道ContiguousArray、Array還有ArraySlice的大部分屬性和方法是共用的。但是在儲存Class或者@objc 協議時,使用ContiguousArray效率會更高一些。但是ContiguousArray

不能和Objective-C的NSArray進行橋接,並且不能將ContiguousArray傳入到Objective-C的API中。

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

  

二、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一致的話,我們就將其刪除。具體實現如下所示。

  

三、BagElement結構體的實現

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

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

   

四、Bag的延展

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

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

  

五、Bag的迭代器

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

  

六、Bag的測試用例

下方程式碼片段中是對Bag的測試用例。首先我們初始化了一個Bag例項,然後指定其泛型型別為String。緊接著我們又建立了一個bagsTokens的陣列,用來儲存myBags中每個元素所對應的token,便於在移除元素時使用。最後是往myBags中新增值了。每新增一個值我們就記錄一下該值所對應的token。

在新增完元素後,我們可以遍歷輸出一下每個token物件的HashValue。然後我們可以通過token來移除myBags中的元素。

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

  

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

  

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