Swift 語言中提供了一種 for .. in 語法的形式疫蔓,用于遍歷集合含懊,比如對于 Array 類型身冬,就可以用 for .. in 來進行遍歷。這個語法在很多其他語言中也有提供岔乔,省去了我們定義下標(biāo)的操作酥筝。今天我們要了解的就是關(guān)于 for .. in 語法的原理,我們可以讓我們自己的類也支持這個語法雏门。
何為 for .. in
首先嘿歌,我們先來了解一下 for .. in 的用法,比如這段代碼:
let bookList = ["Swift", "iOS", "Objc"]
for bookName in bookList {
print(bookName)
}
我們定義了一個數(shù)組 bookList
茁影, 里面存放了三個字符串宙帝。然后我們就可以通過 for ... in 循環(huán)進行遍歷。
數(shù)組其實就是 Array 類募闲,我們上面的定義如果寫的詳細些步脓,應(yīng)該是這樣:
let bookList:Array = ["Swift", "iOS", "Objc"]
也就是說,我們傳遞給 for ... in 語法的浩螺,其實是一個 Array 類的實例靴患。那么我們再來看看 Array 類的繼承關(guān)系:
public struct Array<Element> : CollectionType, MutableCollectionType, _DestructorSafeContainer {
...
}
它繼承自一個叫做 CollectionType 的協(xié)議,然后我們再來看一下 CollectionType 的定義:
public protocol SequenceType {
...
}
經(jīng)過這么一連串的追溯要出,其實關(guān)鍵就在于這個 SequenceType鸳君,一個類如果實現(xiàn)了 SequenceType 協(xié)議,那么他就可以使用 for ... in 語法進行遍歷了患蹂。包括我們自己的定義的類或颊。
如何實現(xiàn) SequenceType 協(xié)議
那么,既然我們知道了這個特性传于,我們就可以讓自己定義的類也支持 for .. in 語法囱挑。我們先定義一個實體類 Book:
class Book {
var name:String = ""
var price:Float = 0.0
init(name: String, price: Float) {
self.name = name
self.price = price
}
}
Book 類有兩個屬性,一個是書名格了,一個是價格看铆,然后還有一個構(gòu)造方法。
接下來盛末,我們再定義一個類 BookList弹惦,它實現(xiàn)了 SequenceType 協(xié)議,用來表示 Book 實例的列表悄但。不過再實現(xiàn)之前棠隐,我們先看一看 SequenceType 協(xié)議都需要實現(xiàn)那些接口:
class BookList: SequenceType {
...
typealias Generator = BookListGenerator
func generate() -> Generator {
return BookListGenerator(bookList: self.bookList!)
}
}
SequenceType 協(xié)議中定義了一個 typealias Generator 的屬性,這個屬性是一個繼承自 GeneratorType 的類檐嚣。
SequenceType 還定義了一個 generate 方法助泽,用于返回我們指定的 GeneratorType 類型啰扛。
恩。嗡贺。 怎么又多了個 GeneratorType隐解, 好像有點復(fù)雜的樣子。那么咱們繼續(xù)看诫睬,GeneratorType 是實際生成遍歷信息的接口煞茫,我們這里的 BookListGenerator 實現(xiàn)了這個協(xié)議,那就來看一下代碼吧:
class BookListGenerator : GeneratorType {
typealias Element = Book
var currentIndex:Int = 0
var bookList:[Book]?
init(bookList: [Book]) {
self.bookList = bookList
}
func next() -> Element? {
guard let list = bookList else { return nil }
if currentIndex < list.count {
let element = list[currentIndex]
currentIndex++
return element
}else {
return nil
}
}
}
代碼稍長摄凡,請聽我給大家一一分解~
首先续徽,GeneratorType 定義了一個屬性別名: typealias Element。 我們將 Book 類賦值給它亲澡,表示我們這個集合中存儲的數(shù)據(jù)類型是 Book 類的實例钦扭。
接下來,GeneratorType 還定義了一個 next 方法床绪。用于遍歷這個集合客情,直到 next 方法返回 nil 的時候,遍歷結(jié)束会涎。
func next() -> Element? {
guard let list = bookList else { return nil }
if currentIndex < list.count {
let element = list[currentIndex]
currentIndex++
return element
}else {
return nil
}
}
- next 方法中裹匙,先用 guard 關(guān)鍵字進行了一次判斷,檢查 bookList(也就是實際的數(shù)據(jù)是否為空)末秃,如果為空概页,就直接返回 nil。 宣告遍歷結(jié)束~
- 接下來练慕,用了一個叫做 currentIndex 的屬性表示當(dāng)前所遍歷到得索引惰匙,這個屬性的初始值是 0,然后每遍歷一個元素铃将,就加 1项鬼,直到它的值超出 list.count 的值,就會返回 nil劲阎,宣告遍歷完成~
這樣绘盟,我們的 BookListGenerator 就定義完成了(當(dāng)然,它還聲明了一個構(gòu)造方法悯仙,由于實在簡單龄毡,我們就不多說了~)。再次回到繼承自 SequenceType 的 BookList 類中:
class BookList: SequenceType {
private var bookList:[Book]?
init() {
self.bookList = [Book]()
}
func addBook(book:Book){
self.bookList?.append(book)
}
typealias Generator = BookListGenerator
func generate() -> Generator {
return BookListGenerator(bookList: self.bookList!)
}
}
這次列出了所有的代碼锡垄,還是一一分解~
看了上面關(guān)于 BookListGenerator 類的定義沦零,相信就不難理解這里的代碼了:
typealias Generator = BookListGenerator
func generate() -> Generator {
return BookListGenerator(bookList: self.bookList!)
}
這兩個 SequenceType 接口的方法我們再來觀摩下,typealias 就不用多說了货岭,generate 方法會再遍歷開始的時候調(diào)用一次路操,每次遍歷都會構(gòu)建一個 Generator 實例疾渴,我們這個 BookList 中構(gòu)建的就是 BookListGenerator,并傳入了 self.bookList(這個是實際的數(shù)據(jù)列表)以供 BookListGenerator 來進行具體的遍歷操作屯仗。
其他方面嘛搞坝,BookList 類還定了一個私有屬性,用于實際存放 Book 的列表數(shù)據(jù):
private var bookList:[Book]?
還提供了一個構(gòu)造方法祭钉,和一個 addBook 方法瞄沙,供我們使用,這兩個方法比較簡單慌核,就不多說啦。
使用我們的 SequenceType 類型
好了申尼,我們的 BookList 就這樣完工啦】遄浚現(xiàn)在輪到我們檢驗一下了:
let bookList = BookList()
bookList.addBook(Book(name: "Swift", price: 12.5))
bookList.addBook(Book(name: "iOS" , price: 10.5))
bookList.addBook(Book(name: "Objc", price: 20.0))
for book in bookList {
print("\(book.name) 價格 ¥\(book.price)")
}
大功告成,我們聲明了 BookList 類师幕,然后用 addBook 方法添加幾本書進來粟按。接著我們就可以用 for .. in 來遍歷這個集合啦。
結(jié)語
經(jīng)過這一系列的折騰霹粥,我們實現(xiàn)了 SequenceType 和 GeneratorType 類型的定義灭将,并實現(xiàn) for .. in 的循環(huán)遍歷。以及了解了這背后的原理后控。當(dāng)然庙曙,我在這里也只是給大家介紹了一個點,大家還可以在 swiftdoc.org 查看這幾個協(xié)議的詳細文檔浩淘,里面介紹的更加全面捌朴。
另外,關(guān)于 Swift 語言特性知識的內(nèi)容张抄,還可以看一看這幾篇內(nèi)容:
最后,感謝大家花了這么長時間把這篇文章看完署惯。希望給大家提供更多有價值的內(nèi)容左驾,期待大家的寶貴意見。
更多精彩內(nèi)容可關(guān)注微信公眾號:
swift-cafe