今天博客我接着上篇博客的內容來,上篇博客咱們詳細的看了ReactiveSwift中的Observer已經Event的代碼實現。接下來咱們來看一下ReactiveSwift中的結構體Bag的實現。Bag:袋子,顧明思議,就是用來裝東西的,咱們暫且將Bag稱之爲容器。在ReactiveSwift中的Bag主要是用來存儲Signal對象的,咱們在後期介紹ReactiveSwift源碼時會陸陸續續的看到Bag的身影。html
由於Bag這個結構體在ReactiveSwift中比較獨立,因此咱們本篇博客就來聊一下Bag的具體實現。本篇博客咱們會詳細的介紹Bag的代碼實現,並從Bag代碼實現中看一下Swift語言自己的東西,並給出Bag的測試用例。固然,本篇博客咱們還會涉及到「迭代器模式」,關於「迭代器模式」更詳細的信息,請移步於以前發佈的關於設計模式的博客《設計模式(十):從電影院中認識"迭代器模式"(Iterator Pattern)》。git
1、ContiguousArraygithub
在博客的第一部分咱們先來看一下ContiguousArray的相關內容。由於結構體Bag就是在ContiguousArray的基礎上進行封裝的,也就是說袋子中的元素最終是存放在ContiguousArray中的。在Swift中ContiguousArray與Array的用法差很少,下方是官方對ContiguousArray的介紹。設計模式
從下方咱們能夠清楚的知道ContiguousArray、Array還有ArraySlice的大部分屬性和方法是共用的。可是在存儲Class或者@objc 協議時,使用ContiguousArray效率會更高一些。可是ContiguousArray不能和Objective-C的NSArray進行橋接,而且不能將ContiguousArray傳入到Objective-C的API中。
數組
固然從ContiguousArray名字來看,它是佔用連續存儲空間的數組。具體請看下方的官方介紹。app
2、Bag的基本實現post
下方是結構體Bag的基本實現,稍後還會介紹Bag的延展以及與其關聯的BagElement類型。接下來咱們來詳細的看一下其實現。固然下方截圖中的代碼實現,是將ReactiveSwift中的英文註釋給刪了,添加了一些中文註釋。這樣看着更舒服一些。測試
一、RemovalTokenurl
首先咱們來看一下RemovalToken,以及看一下RemovalToken這個類在Bag結構體中所扮演的角色。從下方代碼片斷中咱們不難看出,RemovalToken是一個空類,中該類的名字咱們能夠看出,該類的對象是充當Token用的。也就是說該類的對象能夠做爲Bag中所存儲元素的惟一標示符,而且能夠用來刪除元素使用。spa
咱們知道,每一個類的對象都會有一個惟一的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一致的話,咱們就將其刪除。具體實現以下所示。
3、BagElement結構體的實現
接下來,咱們來看一下Bag中所存儲元素的類型BagElement的實現,代碼以下所示。固然實現比較簡單,BagElement也是一個泛型結構體,其泛型類型Value其實就是Bag的泛型類型Element。其中有兩個屬性,一個Value,用來存儲值。另外一個是token,用來存儲該值對應的惟一標示。
緊接着是BagElement的的延展,用來輸出描述信息的,以下所示。
4、Bag的延展
接下來咱們來看一下Bag的延展,代碼以下所示。Bag的延展中的相關內容仍是比較簡單的。首先定義了一個Array<Element>.Index的類型別名Index,其實就是Int類型。而後是startIndex和endIndex兩個計算屬性,用來獲取Bag的第一個元素的索引,和結束位置的索引。
subscript()方法是爲Bag結構體添加自定義下標,使其支持下標訪問元素的形式。makeIterator()方法則用來建立Bag<Element>所對應的迭代器。關於Bag的迭代器,稍後會進行介紹。
5、Bag的迭代器
接下來我咱們就來看一下Bag容器的迭代器,其實就是「迭代器模式」的具體應用。下方代碼段就是Bag的迭代器的具體實現。從下方代碼咱們不難看出,BagIterator實現了Swift中的迭代器協議IteratorProtocol,而後給出了迭代器的next()方法的實現。下方咱們將會對該迭代器進行測試。
6、Bag的測試用例
下方代碼片斷中是對Bag的測試用例。首先咱們初始化了一個Bag實例,而後指定其泛型類型爲String。緊接着咱們又建立了一個bagsTokens的數組,用來存儲myBags中每一個元素所對應的token,便於在移除元素時使用。最後是往myBags中添加值了。每添加一個值咱們就記錄一下該值所對應的token。
在添加完元素後,咱們能夠遍歷輸出一下每一個token對象的HashValue。而後咱們能夠經過token來移除myBags中的元素。
最後咱們能夠從myBags中獲取相應的迭代器,而後使用迭代器訪問myBags中的元素。
下方是對Bag中的Token以及Bag中的全部元素進行的輸出,以下所示:
今天博客就先到這兒,下篇博客會繼續更新ReactiveSwift相關的東西。
上述代碼github分享地址:https://github.com/lizelu/TipSwiftForRac