Swift 提供了类似 C 语言的流程控制结构,包括可以多次执行任务的for
和while
循环,基于特定条件选择执行不同代码分支的if
、guard
和switch
语句,还有控制流程跳转到其他代码的break
和continue
语句。
除了 C 语言里面传统的 for 循环,Swift 还增加了for-in
循环,用来更简单地遍历数组(array),字典(dictionary),区间(range),字符串(string)和其他序列类型。
Swift 的switch
语句比 C 语言中更加强大。在 C 语言中,如果某个 case 不小心漏写了break
,这个 case 就会贯穿至下一个 case,Swift 无需写break
,所以不会发生这种贯穿的情况。case 还可以匹配更多的类型模式,包括区间匹配(range matching),元组(tuple)和特定类型的描述。switch
的 case 语句中匹配的值可以是由 case 体内部临时的常量或者变量决定,也可以由where
分句描述更复杂的匹配条件.
For-In
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
Repeat-While
Swift语言的repeat-while
循环合其他语言中的do-while
循环是类似的。
Switch
switch
语句必须是完备的。这就是说,每一个可能的值都必须至少有一个 case
分支与之对应。在某些不可能涵盖所有值的情况下,你可以使用默认(default
)分支满足该要求,这个默认分支必须在switch
语句的最后面。
不存在隐式的贯穿(No Implicit Fallthrough)
与 C
语言和 Objective-C
中的switch
语句不同,在 Swift 中,当匹配的 case
分支中的代码执行完毕后,程序会终止switch
语句,而不会继续执行下一个 case
分支。这也就是说,不需要在 case
分支中显式地使用break语句。这使得switch
语句更安全、更易用,也避免了因忘记写break
语句而产生的错误。
ps:虽然在Swift中
break
不是必须的,但你依然可以在case
分支中的代码执行完毕前使用break
跳出.
如果想要贯穿至特定的 case 分支中,请使用fallthrough语句.
区间匹配
case 分支的模式也可以是一个值的区间。下面的例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式:
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."
ps: 闭区间操作符(
...
)以及半开区间操作符(..<
)功能被重载去返回IntervalType
或Range
。一个区间可以决定他是否包含特定的元素,就像当匹配一个switch
声明的case
一样。区间是一个连续值的集合,可以用for-in
语句遍历它。
值绑定(Value Bindings)
case
分支的模式允许将匹配的值绑定到一个临时的常量或变量,这些常量或变量在该 case
分支里就可以被引用了——这种行为被称为值绑定(value binding)。
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"
Where
case 分支的模式可以使用where
语句来判断额外的条件。
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"
控制转移语句(Control Transfer Statements)
控制转移语句改变你代码的执行顺序,通过它你可以实现代码的跳转。Swift 有五种控制转移语句:
continue
break
fallthrough
return
throw
贯穿(Fallthrough)
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."
ps:
fallthrough
关键字不会检查它下一个将会落入执行的case
中的匹配条件。fallthrough
简单地使代码执行继续连接到下一个case
中的执行代码,这和C
语言标准中的switch
语句特性是一样的。
带标签的语句
在 Swift 中,你可以在循环体和switch
代码块中嵌套循环体和switch
代码块来创造复杂的控制流结构。然而,循环体和switch
代码块两者都可以使用break
语句来提前结束整个方法体。因此,显式地指明break
语句想要终止的是哪个循环体或者switch
代码块,会很有用。类似地,如果你有许多嵌套的循环体,显式指明continue
语句想要影响哪一个循环体也会非常有用。
为了实现这个目的,你可以使用标签来标记一个循环体或者switch
代码块,当使用break
或者continue
时,带上这个标签,可以控制该标签代表对象的中断或者执行。
产生一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,并且该标签后面还需带着一个冒号。下面是一个while
循环体的语法,同样的规则适用于所有的循环体和switch
代码块。
label name: while condition {
statements
}
提前退出
像if
语句一样,guard
的执行取决于一个表达式的布尔值。我们可以使用guard
语句来要求条件必须为真时,以执行guard
语句后的代码。不同于if
语句,一个guard
语句总是有一个else
分句,如果条件不为真则执行else
分句中的代码。
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(["name": "John"])
// prints "Hello John!"
// prints "I hope the weather is nice near you."
greet(["name": "Jane", "location": "Cupertino"])
// prints "Hello Jane!"
// prints "I hope the weather is nice in Cupertino."
如果条件不被满足,在else
分支上的代码就会被执行。这个分支必须转移控制以退出guard
语句出现的代码段。它可以用控制转移语句如return
,break
,continue
或者throw
做这件事,或者调用一个不返回的方法或函数,例如fatalError()
。
检测 API 可用性
Swift 有检查 API 可用性的内置支持,这可以确保我们不会不小心地使用对于当前部署目标不可用的 API。
编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 API,Swift 会在编译期报错。
我们使用一个可用性条件在一个if
或guard
语句中去有条件的执行一段代码,这取决于我们想要使用的 API 是否在运行时是可用的。编译器使用从可用性条件语句中获取的信息去验证在代码块中调用的 API 是否都可用。
if #available(iOS 9, OSX 10.10, *) {
// 在 iOS 使用 iOS 9 的 API, 在 OS X 使用 OS X v10.10 的 API
} else {
// 使用先前版本的 iOS 和 OS X 的 API
}
以上可用性条件指定了在 iOS 系统上,if
段的代码仅会在 iOS 9 及更高版本的系统上执行;在 OS X,仅会在 OS X v10.10 及更高版本的系统上执行。最后一个参数,*
,是必须写的,用于处理未来潜在的平台。
在它的一般形式中,可用性条件获取了一系列平台名字和版本。平台名字可以是iOS
,OSX
或watchOS
。除了特定的主板本号像 iOS 8,我们可以指定较小的版本号像 iOS 8.3 以及 OS X v10.10.3。
if #available(platform name version, ..., *) {
statements to execute if the APIs are available
} else {
fallback statements to execute if the APIs are unavailable
}