4 控制流(Control Flow)
4.1 For-In Loops
用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
index是一个在每次循环开始是给定常数,因此不必提前声明。它的声明隐式的包含在循环体声明中,省略了let关键字。
如果不需要序列中的每个值,可以用下划线代替index忽略掉这些值。
let base = 3
let power = 10
var answer = 1
for _ in 1...power {
answer *= base
}
print("(base) to the power of (power) is (answer)")
// Prints "3 to the power of 10 is 59049"
由于循环的目的只是计数,每次的值是不用的,因此可以忽略。
用for-in遍历数组元素。
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, (name)!")
}
// Hello, Anna! // Hello, Alex! // Hello, Brian! // Hello, Jack!
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("(animalName)s have (legCount) legs")
}
// ants have 6 legs // cats have 4 legs // spiders have 8 legs
由于Dictionary中的数据对在本质上是无序存放的,遍历的结果不一定与保存的顺序一致。
4.2 While Loops
while循环运行一系列语句直到条件变成 false。当循环次数在开始时不能确定时用while循环。Swift提供了2种while循环:
while evaluates its condition at the start of each pass through the loop.
repeat-while evaluates its condition at the end of each pass through the loop.
While
while condition {
statements
}
如果条件不满足就不执行。下面是一个例子:
The rules of the game are as follows:
- The board has 25 squares, and the aim is to land on or beyond square 25.
- Each turn, you roll a six-sided dice and move by that number of squares, following the horizontal path indicated by the dotted arrow above.
- If your turn ends at the bottom of a ladder, you move up that ladder.
- If your turn ends at the head of a snake, you move down that snake.
- let finalSquare = 25
- var board = [Int](count: finalSquare + 1, repeatedValue: 0)
- board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
- board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
- var square = 0
- var diceRoll = 0
- while square < finalSquare {
- // roll the dice
- diceRoll += 1
- if diceRoll == 7 { diceRoll = 1 }
- // move by the rolled amount
- square += diceRoll
- if square < board.count {
- // if we're still on the board, move up or down for a snake or a ladder
- square += board[square]
- }
- }
- print("Game over!")
Repeat-While
在判断条件前先执行一次循环体。
repeat {
statements
} while condition
repeat {
// move up or down for a snake or ladder
square += board[square]
// roll the dice
diceRoll += 1
if diceRoll == 7 { diceRoll = 1 }
// move by the rolled amount
square += diceRoll
} while square < finalSquare
print("Game over!")
4.3 条件语句 Conditional Statements
Swift提供两种类型的条件语句:if 语句和switch语句。通常,当条件较为简单且可能的情况很少时,使用if语句。而switch语句更适用于条件较复杂、可能情况较多且需要用到模式匹配(pattern-matching)的情境。
IF
var temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
print("It's really warm. Don't forget to wear sunscreen.")
} else {
print("It's not that cold. Wear a t-shirt.")
}
Switch
switch some value to consider {
case value 1:
respond to value 1
case value 2, value 3:
respond to value 2 or 3
default:
otherwise, do something else
}
与if语句类似,每一个case是一个独立的代码执行分支。switch语句确定选择哪一个分支。
每个switch语句必须包含所有各种可能性(各种cases)。如果不能穷举各种可能性,可以用default case包含前面没有显示标明的其它各种可能,default case必须放在最后。
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")
}
No Implicit Fallthrough
switch不会直落,执行完一个case,自然退出switch,不会下落到下一个case。如果要包含多个值,用逗号列举。
switch some value to consider {
case value 1,
value 2:
statements
}
Interval Matching
A switch可以用区间值(范围)。
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).")
Tuples
A switch可以用元组数据,switch确定是在原点(0, 0)、x轴(_, 0)、y轴(0, _)、篮框内(-2...2, -2...2)(范围值)还是蓝框外default。
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")//蓝框外
}
Value Bindings
A switch case可以将匹配的值绑定到一个临时常量或变量上。switch确定是在x轴(_, 0)、y轴(0, _)或者其它任意点。
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))")
}
Where
switch的case可以使用where检查额外的条件。switch确定是在满足x=y的绿线上、在满足x=-y的紫线上或者其它任意点。
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")
}
4.4 控制转移Control Transfer Statements
控制转移语句改变代码的执行顺序,实现代码的跳转。Swift 有五种控制转移语句:continue、break、fallthrough、return、throw。
Continue
continue语句告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。
letpuzzleInput = "great minds think alike"
var puzzleOutput = ""
for character in puzzleInput.characters {
switch character {
case "a", "e", "i", "o", "u", " ":
continue
default:
puzzleOutput.append(character)
}
}
print(puzzleOutput)
Break
break语句会立刻结束整个控制流的执行。
循环语句中的 break
循环体中break会立刻中断该循环体的执行,然后跳转到表示循环体结束的大括号( } )后的第一行代码。
Switch语句中的break
switch代码块中break会立即中断该switch代码块的执行,跳转到表示switch代码块结束的大括号( } )后的第一行代码。
下面是switch中break的例子。
let numberSymbol: Character = "三"
var possibleIntegerValue: Int?
switch numberSymbol {
case "1", "١", "一", "๑":
possibleIntegerValue = 1
case "2", "٢", "二", "๒":
possibleIntegerValue = 2
case "3", "٣", "三", "๓":
possibleIntegerValue = 3
case "4", "٤", "四", "๔":
possibleIntegerValue = 4
default:
break
}
if let integerValue = possibleIntegerValue {
print("The integer value of (numberSymbol) is (integerValue).")
} else {
print("An integer value could not be found for (numberSymbol).")
}
Fallthrough
swift中的switch不会从上一个case分支落入到下一个case分支中。如果确实需要C风格的贯穿特性,可以在每个需要该特性的case分支中使用 fallthrough关键字。下面是使用 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)
带标签的语句Labeled Statements
循环体和switch代码块两者都可以使用break语句来提前结束。因此,显式地指明break语句想要终止的是哪个循环体或者switch代码块,会很有用。类似地,如果你有许多嵌套的循环体,显式指明continue语句想要影响哪一个循环体也会非常有用。
为了实现这个目的,你可以使用标签来标记一个循环体或者switch 代码块,当使用break或者continue时,带上这个标签,可以控制该标签代表对象的中断或者执行。
label name: while condition {
statements
}
gameLoop: while square != finalSquare {
diceRoll += 1
if diceRoll == 7 { diceRoll = 1 }
switch square + diceRoll {
case finalSquare:
// diceRoll will move us to the final square, so the game is over
break gameLoop
case let newSquare where newSquare > finalSquare:
// diceRoll will move us beyond the final square, so roll again
continue gameLoop
default:
// this is a valid move, so find out its effect
square += diceRoll
square += board[square]
}
}
print("Game over!")
4.5 提前退出Early Exit
像if语句一样, guard的执行取决于一个表达式的布尔值。我们可以使用guard 语句来要求条件必须为真时,以执行guard语句后的代码。不同于 if 语句,一个 guard 语句总是有一个else分句,如果条件不为真则执行else分句中的代码。
funcgreet(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."
4.6 检测API有效性 Checking API Availability
Swift 有检查 API 可用性的内置支持,这可以确保我们不会不小心地使用对于当前部署目标不可用的 API。
if #available(iOS 9, OSX 10.10, *) {
// Use iOS 9 APIs on iOS, and use OS X v10.10 APIs on OS X
} else {
// Fall back to earlier iOS and OS X APIs
}
我们使用一个可用性条件在一个 if 或 guard 语句中去有条件的执行一段代码,这取决于我们想要使用的 API 是否在运行时是可用的。编译器使用从可用性条件语句中获取的信息去验证在代码块中调用的 API 是否都可用。
if #available(platform name version, ..., *) {
statements to execute if the APIs are available
} else {
fallback statements to execute if the APIs are unavailable
}