For-In 循環(huán)
你可以使用for-in循環(huán)來遍歷一個(gè)集合中的所有元素,例如數(shù)字范圍、數(shù)組中的元素或者字符串中的字符。
下面的例子用來輸出乘 5 乘法表前面一部分內(nèi)容:
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25```
##While 循環(huán)
while循環(huán)會(huì)一直運(yùn)行一段語句直到條件變成false。這類循環(huán)適合使用在第一次迭代前,迭代次數(shù)未知的情況下。Swift 提供兩種while循環(huán)形式:
while循環(huán),每次在循環(huán)開始時(shí)計(jì)算條件是否符合;
repeat-while循環(huán),每次在循環(huán)結(jié)束時(shí)計(jì)算條件是否符合
##不存在隱式的貫穿
與 C 和 Objective-C 中的switch語句不同,在 Swift 中,當(dāng)匹配的 case 分支中的代碼執(zhí)行完畢后,程序會(huì)終止switch語句,而不會(huì)繼續(xù)執(zhí)行下一個(gè) case 分支。這也就是說,不需要在 case 分支中顯式地用break語句。這使得switch語句更安全、更易用,也避免了因忘記寫break語句而產(chǎn)生的錯(cuò)誤。
注意: 雖然在Swift中break不是必須的,但你依然可以在 case 分支中的代碼執(zhí)行完畢前使用break
跳出,詳情請(qǐng)參見[Switch 語句中的 break](http://www.swift51.com/swift3.0/chapter2/05_Control_Flow.html#break_in_a_switch_statement)。
每一個(gè) case 分支都*必須*包含至少一條語句。像下面這樣書寫代碼是無效的,因?yàn)榈谝粋€(gè) case 分支是空的:
let anotherCharacter: Character = "a"switch anotherCharacter {
case "a": // 無效,這個(gè)分支下面沒有語句
case "A":
print("The letter A")default: print("Not the letter A")}// 這段代碼會(huì)報(bào)編譯錯(cuò)誤
為了讓單個(gè)case同時(shí)匹配a和A,可以將這個(gè)兩個(gè)值組合成一個(gè)復(fù)合匹配,并且用逗號(hào)分開:
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
print("The letter A")
default:
print("Not the letter A")
}
// 輸出 "The letter A
##區(qū)間匹配
case 分支的模式也可以是一個(gè)值的區(qū)間。下面的例子展示了如何使用區(qū)間匹配來輸出任意數(shù)字對(duì)應(yīng)的自然語言格式:
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
var naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are (naturalCount) (countedThings).")
// 輸出 "There are dozens of moons orbiting Saturn."```
元組
我們可以使用元組在同一個(gè)switch語句中測(cè)試多個(gè)值。元組中的元素可以是值,也可以是區(qū)間。另外,使用下劃線(_)來匹配所有可能的值。
下面的例子展示了如何使用一個(gè)(Int, Int)類型的元組來分類下圖中的點(diǎn)(x, y):
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("(0, 0) is at the origin")
case (_, 0):
print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
print("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// 輸出 "(1, 1) is inside the box"```
##元組
我們可以使用元組在同一個(gè)switch語句中測(cè)試多個(gè)值。元組中的元素可以是值,也可以是區(qū)間。另外,使用下劃線(_)來匹配所有可能的值。
下面的例子展示了如何使用一個(gè)(Int, Int)類型的元組來分類下圖中的點(diǎn)(x, y):
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("(0, 0) is at the origin")
case (_, 0):
print("((somePoint.0), 0) is on the x-axis")
case (0, _):
print("(0, (somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
print("((somePoint.0), (somePoint.1)) is inside the box")
default:
print("((somePoint.0), (somePoint.1)) is outside of the box")
}
// 輸出 "(1, 1) is inside the box"```

在上面的例子中,switch語句會(huì)判斷某個(gè)點(diǎn)是否是原點(diǎn)(0, 0),是否在紅色的x軸上,是否在橘黃色的y軸上,是否在一個(gè)以原點(diǎn)為中心的4x4的藍(lán)色矩形里,或者在這個(gè)矩形外面。
不像 C 語言,Swift 允許多個(gè) case 匹配同一個(gè)值。實(shí)際上,在這個(gè)例子中,點(diǎn)(0, 0)可以匹配所有四個(gè) case。但是,如果存在多個(gè)匹配,那么只會(huì)執(zhí)行第一個(gè)被匹配到的 case 分支??紤]點(diǎn)(0, 0)會(huì)首先匹配case (0, 0),因此剩下的能夠匹配的分支都會(huì)被忽視掉。
值綁定(Value Bindings)
case 分支允許將匹配的值綁定到一個(gè)臨時(shí)的常量或變量,并且在case分支體內(nèi)使用 —— 這種行為被稱為值綁定(value binding),因?yàn)槠ヅ涞闹翟赾ase分支體內(nèi),與臨時(shí)的常量或變量綁定。
下面的例子展示了如何在一個(gè)(Int, Int)類型的元組中使用值綁定來分類下圖中的點(diǎn)(x, y):
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
// 輸出 "on the x-axis with an x value of 2"```

在上面的例子中,switch語句會(huì)判斷某個(gè)點(diǎn)是否在紅色的x軸上,是否在橘黃色的y軸上,或者不在坐標(biāo)軸上。
這三個(gè) case 都聲明了常量x和y的占位符,用于臨時(shí)獲取元組anotherPoint的一個(gè)或兩個(gè)值。第一個(gè) case ——case (let x, 0)將匹配一個(gè)縱坐標(biāo)為0的點(diǎn),并把這個(gè)點(diǎn)的橫坐標(biāo)賦給臨時(shí)的常量x。類似的,第二個(gè) case ——case (0, let y)將匹配一個(gè)橫坐標(biāo)為0的點(diǎn),并把這個(gè)點(diǎn)的縱坐標(biāo)賦給臨時(shí)的常量y。
一旦聲明了這些臨時(shí)的常量,它們就可以在其對(duì)應(yīng)的 case 分支里使用。在這個(gè)例子中,它們用于打印給定點(diǎn)的類型。
請(qǐng)注意,這個(gè)switch語句不包含默認(rèn)分支。這是因?yàn)樽詈笠粋€(gè) case ——case let(x, y)聲明了一個(gè)可以匹配余下所有值的元組。這使得switch語句已經(jīng)完備了,因此不需要再書寫默認(rèn)分支。
Where
case 分支的模式可以使用where語句來判斷額外的條件。
下面的例子把下圖中的點(diǎn)(x, y)進(jìn)行了分類:
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("((x), (y)) is on the line x == y")
case let (x, y) where x == -y:
print("((x), (y)) is on the line x == -y")
case let (x, y):
print("((x), (y)) is just some arbitrary point")
}
// 輸出 "(1, -1) is on the line x == -y"```

在上面的例子中,switch語句會(huì)判斷某個(gè)點(diǎn)是否在綠色的對(duì)角線x == y上,是否在紫色的對(duì)角線x == -y上,或者不在對(duì)角線上。
這三個(gè) case 都聲明了常量x和y的占位符,用于臨時(shí)獲取元組yetAnotherPoint的兩個(gè)值。這兩個(gè)常量被用作where語句的一部分,從而創(chuàng)建一個(gè)動(dòng)態(tài)的過濾器(filter)。當(dāng)且僅當(dāng)where語句的條件為true時(shí),匹配到的 case 分支才會(huì)被執(zhí)行。
就像是值綁定中的例子,由于最后一個(gè) case 分支匹配了余下所有可能的值,switch語句就已經(jīng)完備了,因此不需要再書寫默認(rèn)分支
復(fù)合匹配
當(dāng)多個(gè)條件可以使用同一種方法來處理時(shí),可以將這幾種可能放在同一個(gè)case
后面,并且用逗號(hào)隔開。當(dāng)case后面的任意一種模式匹配的時(shí)候,這條分支就會(huì)被匹配。并且,如果匹配列表過長(zhǎng),還可以分行書寫:
let someCharacter: Character = "e"switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l",
"m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("\(someCharacter) is a consonant")
default:
print("\(someCharacter) is not a vowel or a consonant")
}
// 輸出 "e is a vowel"
這個(gè)switch
語句中的第一個(gè)case,匹配了英語中的五個(gè)小寫元音字母。相似的,第二個(gè)case匹配了英語中所有的小寫輔音字母。最終,default
分支匹配了其它所有字符。 復(fù)合匹配同樣可以包含值綁定。復(fù)合匹配里所有的匹配模式,都必須包含相同的值綁定。并且每一個(gè)綁定都必須獲取到相同類型的值。這保證了,無論復(fù)合匹配中的哪個(gè)模式發(fā)生了匹配,分支體內(nèi)的代碼,都能獲取到綁定的值,并且綁定的值都有一樣的類型。
let stillAnotherPoint = (9, 0)
switch stillAnotherPoint {
case (let distance, 0), (0, let distance):
print("On an axis, \(distance) from the origin")
default: print("Not on an axis")
}
// 輸出 "On an axis, 9 from the origin"
上面的case有兩個(gè)模式:(let distance, 0)匹配了在x軸上的值,(0, let distance)匹配了在y軸上的值。兩個(gè)模式都綁定了distance,并且distance在兩種模式下,都是整型——這意味著分支體內(nèi)的代碼,只要case匹配,都可以獲取到distance值
控制轉(zhuǎn)移語句
控制轉(zhuǎn)移語句改變你代碼的執(zhí)行順序,通過它可以實(shí)現(xiàn)代碼的跳轉(zhuǎn)。Swift 有五種控制轉(zhuǎn)移語句:
continue
break
fallthrough
return
throw
貫穿
Swift 中的switch不會(huì)從上一個(gè) case 分支落入到下一個(gè) case 分支中。相反,只要第一個(gè)匹配到的 case 分支完成了它需要執(zhí)行的語句,整個(gè)switch代碼塊完成了它的執(zhí)行。相比之下,C 語言要求你顯式地插入break語句到每個(gè) case 分支的末尾來阻止自動(dòng)落入到下一個(gè) case 分支中。Swift 的這種避免默認(rèn)落入到下一個(gè)分支中的特性意味著它的switch 功能要比 C 語言的更加清晰和可預(yù)測(cè),可以避免無意識(shí)地執(zhí)行多個(gè) case 分支從而引發(fā)的錯(cuò)誤。
如果你確實(shí)需要 C 風(fēng)格的貫穿的特性,你可以在每個(gè)需要該特性的 case 分支中使用fallthrough關(guān)鍵字。下面的例子使用fallthrough來創(chuàng)建一個(gè)數(shù)字的描述語句。
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// 輸出 "The number 5 is a prime number, and also an integer."
這個(gè)例子定義了一個(gè)String類型的變量description并且給它設(shè)置了一個(gè)初始值。函數(shù)使用switch邏輯來判斷integerToDescribe變量的值。當(dāng)integerToDescribe的值屬于列表中的質(zhì)數(shù)之一時(shí),該函數(shù)在description后添加一段文字,來表明這個(gè)數(shù)字是一個(gè)質(zhì)數(shù)。然后它使用fallthrough關(guān)鍵字來“貫穿”到default分支中。default分支在description的最后添加一段額外的文字,至此switch代碼塊執(zhí)行完了。
如果integerToDescribe的值不屬于列表中的任何質(zhì)數(shù),那么它不會(huì)匹配到第一個(gè)switch分支。而這里沒有其他特別的分支情況,所以integerToDescribe匹配到default分支中。
當(dāng)switch代碼塊執(zhí)行完后,使用print(_:separator:terminator:)函數(shù)打印該數(shù)字的描述。在這個(gè)例子中,數(shù)字5被準(zhǔn)確的識(shí)別為了一個(gè)質(zhì)數(shù)。
注意: fallthrough關(guān)鍵字不會(huì)檢查它下一個(gè)將會(huì)落入執(zhí)行的 case 中的匹配條件。fallthrough簡(jiǎn)單地使代碼繼續(xù)連接到下一個(gè) case 中的代碼,這和 C 語言標(biāo)準(zhǔn)中的switch語句特性是一樣的。
檢測(cè) API 可用性
Swift內(nèi)置支持檢查 API 可用性,這可以確保我們不會(huì)在當(dāng)前部署機(jī)器上,不小心地使用了不可用的API。
編譯器使用 SDK 中的可用信息來驗(yàn)證我們的代碼中使用的所有 API 在項(xiàng)目指定的部署目標(biāo)上是否可用。如果我們嘗試使用一個(gè)不可用的 API,Swift 會(huì)在編譯時(shí)報(bào)錯(cuò)。
我們?cè)趇f或guard語句中使用可用性條件(availability condition)去有條件的執(zhí)行一段代碼,來在運(yùn)行時(shí)判斷調(diào)用的API是否可用。編譯器使用從可用性條件語句中獲取的信息去驗(yàn)證,在這個(gè)代碼塊中調(diào)用的 API 是否可用。
if #available(iOS 10, macOS 10.12, *) {
// 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API
} else {
// 使用先前版本的 iOS 和 macOS 的 API
}
以上可用性條件指定,在iOS中,if語句的代碼塊僅僅在 iOS 10 及更高的系統(tǒng)下運(yùn)行;在 macOS中,僅在 macOS 10.12 及更高才會(huì)運(yùn)行。最后一個(gè)參數(shù),*,是必須的,用于指定在所有其它平臺(tái)中,如果版本號(hào)高于你的設(shè)備指定的最低版本,if語句的代碼塊將會(huì)運(yùn)行。在它一般的形式中,可用性條件使用了一個(gè)平臺(tái)名字和版本的列表。平臺(tái)名字可以是iOS,macOS,watchOS和tvOS
——請(qǐng)?jiān)L問聲明屬性來獲取完整列表。除了指定像 iOS 8的主板本號(hào),我們可以指定像iOS 8.3 以及 macOS 10.10.3的子版本號(hào)。
if #available(platform name version, ..., *) {
APIs 可用,語句將執(zhí)行
} else {
APIs 不可用,語句將不執(zhí)行
}