今天是元宵節,祝你們元宵節快樂!在Swift中的數組和字典中下標是很是常見的,數組能夠經過索引下標進行元素的查詢,字典能夠經過鍵下標來獲取相應的值。在使用數組時,一個常見的致命錯誤就是數組越界。若是在你的應用程序中數組越界了,那麼對不起,若是由着程序的性子的話是會崩潰的。爲了防止崩潰呢,咱們會對集合作一些安全的處理。好比對數組進行擴展,從而對數組的索引進行安全檢查,保證數組的index在正常範圍內。在Objective-C中也是常常對數組,字典等作一些處理操做。數組
今天的博客的主要內容是先對Objective-C中經常使用集合的安全擴展進行介紹,由此在窺探一下Swift語言中的處理。而且還會介紹Swift中自定義下標,說白了自定義下標其實就是經過下標的形式與特定的下標值來訪問一個對象。自定義下標在有些場合中是很是實用的。而後下方還會給出數組切片的概念與實用方式。廢話少說進入今天的主題。安全
1、安全的索引集合元素app
對一個集合索引進行安全檢查是頗有必要的,也是常常實用的,最多見的就是對數組和字典索引的安全檢查,該部份內容就是類比這Objective-C中的數組索引的安全檢查來擴充Swift的數組,從而讓你的Swift數組也一樣具有對數組安全檢查的功能。函數
1. Objective-C中NSArray對索引的安全擴展測試
下方這段代碼是很是簡單的,它是對Objective-C中的NSArray作的擴展,該方法位於NSArray相關的延展中。在你的項目中,若是添加了此段延展代碼,那麼你就能夠經過objectAtIndexSafe:方法對數組進行安全的索引。有代碼不難看出在定義該函數參數時,咱們將index聲明爲NSUInteger,也就是正整數,這就排除了你對下標傳入一個負數。緊接着又對index的合法性進行驗證,若是index不在數組有效範圍內,那麼就返回nil。當你查找的元素不存在時,你返回nil是不會形成程序崩潰的,由於nil的地址是0x0, 這和歸零若引用有些相似。spa
固然下方只是NSArray安全擴展其中一個方法,還有許多擴展的安全方法,好比數組的增刪改查均可以進行相應的安全擴展,擴展的方式和思路與下方這段簡單代碼相似,再次就不花過多的篇幅對其進行介紹了。3d
1 - (id)objectAtIndexSafe:(NSUInteger)index { 2 if (index > self.count-1) { 3 return nil; 4 } 5 return [self objectAtIndex:index]; 6 }
2.Swift中對Array的安全擴展rest
上面簡單的對Objective-C中的安全方法進行了簡單的介紹,就算是對Swift相關內容的引子吧,下方將會給出Swift語言中相似的方法。對Swift相關方法介紹時,我會盡可能的詳細一些,由於畢竟本篇博客主要是關於Swift內容的。接下來將對上面Objective-C中NSArray數組索引安全驗證的方法使用Swift語言進行從新。固然重寫的內容也是很是容易理解的。code
(1)主要是對subscript方法進行重載,在重載的subscript方法中,對index的範圍經過三目運算符進行了安全檢查。若是index在0..<count這個半開區間內,那麼就返回當前索引的值,若是不在該範圍內就返回nil, 下方就是對Array索引的安全檢查。對象
1 extension Array { 2 subscript (safe index: Int) -> Element? { 3 return (0..<count).contains(index) ? self[index] : nil 4 } 5 }
(2)上面是對Swift中的Array進行了安全索引擴展,接下來就是簡單的使用了,下方的代碼段是對上面安全擴展函數的測試。首先建立了一個數組testArray, 而後建立了一個索引數組indexs, 而後遍歷indexs中的元素值,將其做爲testArray的下標,對testArray進行檢索。固然檢索時,使用的是咱們上面定義的safe方法,而且在indexs下標數組中存在非法的下標。在這種狀況下,咱們來驗證一下咱們的安全方法。
固然在數組遍歷中,咱們使用了for-in循環取出indexs中的每一個index, 而後使用guard語句取出testArray中的值。使用guard語句能很好的過濾掉由於非法的index而返回的nil值。具體代碼段以下所示:
上面的代碼段理解起來並不難,上述測試代碼的運行結果以下所示,從運行結果能夠很好的說明問題,而且在index非法時不會崩潰,併合理的給出相應的錯誤提示,請看下方具體運行結果。
上面的延展也能夠經過對整個集合類型,也就是CollectionType進行擴展,不過在擴展CollectionType時要對Index使用where子句進行限制,使Index必須符合Comparable協議,具體實現以下所示,不過下面的方法比較少用,由於通常是數組存在越界的狀況,由於在字典中,若是你對一個不存在的鍵進行值的索引,會返回nil值,而不會崩潰。可是在數組中,你對不存在的index進行索引,就會拋出錯誤。下方是另外一種處理方式,不過該方式用的比較少。
實現下方延展後,一樣能夠在數組中使用safe方法。
2、使用多個索引下標的數組
延展的功能是很是強大的,該部分將會給出另外一個數組的延展。該延展的功能是能夠經過多個索引給數組設置值,以及經過多個索引一次性獲取多個數組的值。該功能是很是強大的,接下來將一步步實現該功能。
1. 瞭解zip()函數以及Zip2Sequence
在實現數組多個索引擴展時,須要使用到zip()函數,zip()函數接收兩個序列,而且返回一個Zip2Sequence類型的數據。zip()函數到底是幹嗎的呢?接下來將會經過一個小的實例來搞一下zip()函數。首先看一下Apple的幫助文檔上對zip()函數的介紹。具體以下所示:
上面那句英文的意思大概就是「基於兩個基本序列構建了一個序列對,在序列對中,第i對,表明着每一個基本序列中的第i個元素。」在zip函數定義的過程當中,咱們能夠看到,zip()是一個泛型函數,其接收兩個SequenceType類型的參數,而後返回一個Zip2Sequence類型的數據。新建立的序列對就存在於Zip2Sequence中。說這麼多仍是來個小Demo實惠一些,經過一個小實例,看zip()函數的用法一目瞭然。
(1) 建立兩個數組zip1和zip2, 將這兩個數組做爲zip()函數的參數,將兩個數組進行合併。具體實現以下:
(2) 經過上面的程序能夠看出,zipSum是一個Zip2Sequence<Array<Int>, Array<Int>>類型的常量,咱們可使用dump()對zipSum常量進行打印,觀察其中的數據存儲結構,具體結構以下所示:
輸出結果以下,由結果容易看出,在序列中有兩個元素,第一個元素對應着數組zip1, 第二個元素對應着數組zip2。
(3)接下來就是對zipSum這個序列經過for-in循環進行遍歷,下方就是對zipSum進行遍歷的代碼。
上面對zipSum遍歷的結果以下所示,由下方輸出結果可知,輸出是成對遍歷的,若是某個數組中的元素是多餘的,那麼就會被忽略掉。
2. 數組多個索引的延展實現
在這個將要實現的延展中,咱們對Array進行了擴展,在延展中對subscript方法進行重載,使其能夠接受多個下標,而且對多個下標對應的值進行索引,並把索引結果組成數組。在subscript方法中經過get方法獲取索引相應的值,經過set方法爲相應的索引值進行設置。下方代碼段就是該延展的實現:
1 extension Array { 2 subscript(i1: Int, i2: Int, rest: Int...) -> [Element] { 3 //經過實現get方法,獲取數組中相應的值 4 get { 5 var result: [Element] = [self[i1], self[i2]] 6 for index in rest { 7 result.append(self[index]) 8 } 9 return result 10 } 11 12 //經過set方法,對數組相應的索引進行設置 13 set (values) { 14 for (index, value) in zip([i1, i2] + rest, values) { 15 self[index] = value 16 } 17 } 18 } 19 }
在上述延展的實現中,並無多少困難的地方。在subs兩個cript函數中,使用的是可變參數,subscript函數參數的個數是兩個以上(包括兩個)。而後就是經過zip()函數以及對zip()函數返回的結果集進行遍歷,從而對多個下標索引進行值的設置。通過上述延展,咱們就能夠經過多個索引對數組進行操做了。上述延展的使用方式以下:
3、數組切片
數組切片在OC中也是不存在的,是Swift新引入的概念,該部分將會對數組切片進行討論,研究一下數組切片的使用方式及其特色。下方先經過一個小Demo來看一下如何生成數組切片。下方代碼段先將一個字符串經過map函數轉換成一個數組arrayTest, 而後咱們建立一個該數組的切片。下方代碼段建立了arrayTest數組中的下標3到下標6這個範圍區間中的切片,arraySlices就是數組切片變量,它是ArraySlice<String>類型的,具體代碼段以下所示。
在數組切片中有一點須要注意,數組切片的下標與原始數組中的下標保持一致。若是要取出切片arraySlices中的第一個值,咱們要使用arraySlices[3], 而不是arraySlices[0], 若是使用arraySlices[0]就會報錯,以下所示:
由於數組是值類型,儘管切片與原數組有着對應的數組下標,可是切片是原始數組的部分拷貝,因此修改切片或者修改原數組,二者互不影響,下方示例給出了該測試,以下所示:
若是把切片轉換成枚舉,那麼切片中與原始數組對應的下標關係將不存在,下方是將切片轉換成枚舉序列,而後對其進行遍歷,代碼以下:
上述代碼段輸出結果以下:
今天博客就先寫到這兒,關於數組的延展還有許多,之後有機會再討論。其實咱們還能夠經過一些方式來爲咱們本身的對象添加下標。也就是能夠經過下標來訪問對象屬性,這個之後在討論吧。