前提
大家應(yīng)該常遇到在table view的delegate里處理若干個(gè)cell的問題.很多人的條件語(yǔ)句是這樣的:
if indexPath.row == 0 || indexPath.row == 1 || indexPath.row == 3 {
// do something
}
這個(gè)寫法非常常規(guī),也清晰明了.但是致命的缺點(diǎn)是
- 當(dāng)我有更多選項(xiàng)時(shí)長(zhǎng)度已經(jīng)超出字符限制
- 沒有辦法實(shí)現(xiàn)可變數(shù)量的選項(xiàng)
解決方案
簡(jiǎn)單處理下,可以將所有可能放到數(shù)組或者范圍(如果連續(xù))中.然后調(diào)用其contains方法用于校驗(yàn).代碼如下:
if (2...8).contains(indexPath.row) {
// do something
}
if [2,4,6,9].contains(indexPath.row) {
// do something
}
if 2...8 ~= indexPath.row { // 匹配運(yùn)算符
// do something
}
優(yōu)化
這樣雖然解決了前提所述的兩個(gè)問題,但是寫法不夠美觀,語(yǔ)義不夠清晰.如果說可以使用isIn(:)函數(shù)處理,就顯得美觀多了.實(shí)現(xiàn)如下:
// 定義
extension Int {
func isIn(range: Range<Int>) -> Bool {
return range.contains(self)
}
func isIn<T: SequenceType where T.Generator.Element == Int>(ints: T) -> Bool {
return ints.contains(self)
}
func isIn(ints: Int...) -> Bool { //這里使用可變參數(shù)函數(shù)來避免必須將參數(shù)放入數(shù)組
return ints.contains(self)
}
}
// 使用
if indexPath.row.isIn(4,5,6) {
// do something
}
這樣實(shí)現(xiàn)了美觀簡(jiǎn)潔地使用,但是還不夠通用.比如UInt,Float等可以支持Range或數(shù)組的類型卻無(wú)法使用.如果要更加通用,必須研究下contains函數(shù),其定義如下:
extension SequenceType where Generator.Element : Equatable {
/// Returns `true` iff `element` is in `self`.
@warn_unused_result
public func contains(element: Self.Generator.Element) -> Bool
}
那么顯然我們需要擴(kuò)寫Equatable協(xié)議,讓其實(shí)現(xiàn)isIn(:)函數(shù).代碼如下:
extension Equatable {
func isIn<T: SequenceType where T.Generator.Element == Self>(collection: T) -> Bool {
return collection.contains(self)
}
func isIn(collection: Self...) -> Bool {
return collection.contains(self)
}
}
這里需要說明下Range不需額外定義的理由.首先Range的定義如下:
public struct Range<Element : ForwardIndexType> : Equatable, CollectionType, CustomStringConvertible, CustomDebugStringConvertible {...}
它遵循于CollectionType(繼承自SequenceType),它的Element遵循于ForwardIndexType(繼承自Equatable),所以它是符合extension Equatable中第一個(gè)函數(shù)的.
后記
至此,我們用最簡(jiǎn)潔的方式寫出了contains的反函數(shù).這一切要感謝Swift強(qiáng)大的特性支持我們?cè)诓煌S度約束條件,既安全又強(qiáng)大.