Swift의 switch 문은 많은 C 유사 언어의 해당 문보다 훨씬 더 강력합니다. case 간격 일치, 튜플 및 특정 유형으로의 캐스트를 포함하여 다양한 패턴과 일치할 수 있습니다. switch case에서 일치하는 값은 case 본문 내에서 사용하기 위해 임시 상수 또는 변수에 바인딩될 수 있으며 복잡한 일치 조건은 각 case에 대한 where 절로 표현될 수 있습니다.
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")
}
// cats have 4 legs
// ants have 6 legs
// spiders have 8 legs
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
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"
let minutes = 60
for tickMark in 0..<minutes {
// render the tick mark each minute (60 times)
}
stride(from:to:by:)
함수를 사용하여 원하지 않는 표시를 건너뜁니다.```swift
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
// render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
}
```
stride(from(부터):to(전 까지):by(단위로):)
stride(from:through:by:)
를 사용하여 닫힌 범위를 사용할 수도 있습니다.```swift
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
// render the tick mark every 3 hours (3, 6, 9, 12)
}
```
stride(from(부터):through(까지):by(단위로):)
while 루프는 조건이 참이면 조건이 거짓이 될 때까지 일련의 명령문이 반복합니다.
다음은 while 루프의 일반적인 형식입니다.
while condition {
statements
}
아래의 예는 뱀과 사다리의 간단한 게임을 보여줍니다.
let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)
일부 사각형은 뱀과 사다리에 대해 보다 구체적인 값을 갖도록 설정됩니다. 사다리 바닥이 있는 사각형은 보드 위로 이동하는 양수인 반면, 뱀 머리가 있는 사각형은 보드 아래로 다시 이동하는 음수를 갖습니다.
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!")
while 루프가 시작될 때 게임의 길이가 명확하지 않기 때문에 이 경우에 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!")
일반적으로 if 문을 사용하여 몇 가지 가능한 결과만 있는 간단한 조건을 평가합니다.
switch 문은 가능한 순열이 여러 개인 더 복잡한 조건에 더 적합하며 패턴 일치가 실행할 적절한 코드 분기를 선택하는 데 도움이 될 수 있는 상황에서 유용합니다.
var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
}
// Prints "It's very cold. Consider wearing a scarf."
temperatureInFahrenheit = 40
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else {
print("It's not that cold. Wear a t-shirt.")
}
// Prints "It's not that cold. Wear a t-shirt."
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.")
}
// Prints "It's really warm. Don't forget to wear sunscreen."
temperatureInFahrenheit = 72
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.")
}
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
}
let someCharacter: Character = "z"
switch someCharacter {
case "a":
print("The first letter of the alphabet")
case "z":
print("The last letter of the alphabet")
default:
print("Some other character")
}
// Prints "The last letter of the alphabet"
기본적으로 각 사례의 맨 아래를 통과하여 다음 사례로 넘어가지 않습니다.
Swift에서는 break가 필요하지 않지만 break 문을 사용하여 특정 case를 일치 및 무시하거나 해당 case가 실행을 완료하기 전에 일치된 case에서 벗어날 수 있습니다.
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // Invalid, the case has an empty body
case "A":
print("The letter A")
default:
print("Not the letter A")
}
// This will report a compile-time error.
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
print("The letter A")
default:
print("Not the letter A")
}
// Prints "The letter A"
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let 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).")
// Prints "There are dozens of moons orbiting Saturn."
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("\(somePoint) is at the origin")
case (_, 0):
print("\(somePoint) is on the x-axis")
case (0, _):
print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
print("\(somePoint) is inside the box")
default:
print("\(somePoint) is outside of the box")
}
// Prints "(1, 1) is inside the box"
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))")
}
// Prints "on the x-axis with an x value of 2"
이 switch 문에는 기본 case가 없습니다.
마지막 경우인 case let (x, y)는 모든 값과 일치할 수 있는 두 개의 자리 표시자 상수의 튜플을 선언합니다.
anotherPoint는 항상 두 값의 튜플이기 때문에 이 경우는 가능한 모든 나머지 값과 일치하며 기본 경우는 필요하지 않습니다.
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")
}
// Prints "(1, -1) is on the line x == -y"
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) isn't a vowel or a consonant")
}
// Prints "e is a vowel"
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")
}
// Prints "On an axis, 9 from the origin"
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
for character in puzzleInput {
if charactersToRemove.contains(character) {
continue
}
puzzleOutput.append(character)
}
print(puzzleOutput)
// Prints "grtmndsthnklk"
주석만 포함된 switch case는 컴파일 타임 오류로 보고됩니다. 주석은 코드가 아니며 switch case를 무시하지 않습니다. switch case를 무시하려면 항상 break 문을 사용하십시오.
let numberSymbol: Character = "三" // Chinese symbol for the number 3 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 couldn't be found for \(numberSymbol).") } // Prints "The integer value of 三 is 3."
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)
// Prints "The number 5 is a prime number, and also an integer."
Swift에서 다른 루프 및 조건문 내부에 루프 및 조건문을 중첩하여 복잡한 제어 흐름 구조를 생성할 수 있습니다.
그러나 루프와 조건문은 모두 break 문을 사용하여 실행을 조기에 종료할 수 있습니다.
따라서 break 문이 종료되기를 원하는 루프 또는 조건문을 명시하는 것이 때때로 유용합니다.
여러개의 루프 문을 사용하면 break 또는 continue 문과 함께 레이블 문을 사용하여 레이블이 지정된 문의 실행을 종료하거나 continue할 수 있습니다.
레이블이 지정된 명령문은 명령문의 소개 키워드와 같은 줄에 레이블을 배치하고 콜론이 뒤에 오는 것으로 표시됩니다.
label name: while condition {
statements
}
다음 예제에서는 이 장의 앞부분에서 본 Snakes and Ladders 게임의 개조된 버전에 대해 레이블이 지정된 while 루프와 함께 break 및 continue 문을 사용합니다. 이번에는 게임에 추가 규칙이 있습니다.
이 게임 버전은 게임 로직을 구현하기 위해 while 루프와 switch 문을 사용합니다. while 루프에는 뱀과 사다리 게임의 기본 게임 루프임을 나타내는 gameLoop라는 명령문 레이블이 있습니다.
```swift
let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)
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
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!")
```
위의 break 문이 gameLoop 레이블을 사용하지 않은 경우 while 문이 아니라 switch 문에서 중단됩니다. gameLoop 레이블을 사용하면 어떤 제어 문을 종료해야 하는지 명확히 알 수 있습니다.
루프의 다음 반복으로 점프하기 위해 continue gameLoop를 호출할 때 gameLoop 레이블을 사용할 필요는 없습니다.
게임에는 루프가 하나만 있으므로 continue 문이 어떤 루프에 영향을 미칠지 모호하지 않습니다.
그러나 continue 문과 함께 gameLoop 레이블을 사용하는 것은 아무런 문제가 없습니다. 그렇게 하는 것은 break 문과 함께 레이블을 사용하는 것과 일치하며 게임의 논리를 읽고 이해하기 쉽게 만드는 데 도움이 됩니다.
if 문과 같은 guard 문은 표현식의 부울 값에 따라 문을 실행합니다.
guard 문을 사용하여 guard 문 뒤의 코드가 실행되려면 조건이 참이어야 합니다.
if 문과 달리 보호 문에는 항상 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(person: ["name": "John"])
// Prints "Hello John!"
// Prints "I hope the weather is nice near you."
greet(person: ["name": "Jane", "location": "Cupertino"])
// Prints "Hello Jane!"
// Prints "I hope the weather is nice in Cupertino."
guard 문의 조건이 충족되면 guard 문의 닫는 중괄호 뒤에 코드 실행이 계속됩니다.
조건의 일부로 선택적 바인딩을 사용하여 값이 할당된 모든 변수 또는 상수는 guard 문이 표시되는 나머지 코드 블록에 사용할 수 있습니다.
해당 조건이 충족되지 않으면 else 분기 내의 코드가 실행됩니다. 해당 분기는 보호 문이 나타나는 코드 블록을 종료하기 위해 제어를 전송해야 합니다.
return, break, continue, throw와 같은 제어 전달 문으로 이 작업을 수행할 수도 있고, fatalError(_:file:line:)와 같이 반환하지 않는 함수나 메서드를 호출할 수도 있습니다.
요구 사항에 대해 guard 문을 사용하면 if 문으로 동일한 검사를 수행하는 것과 비교하여 코드의 가독성이 향상됩니다.
이를 통해 일반적으로 실행되는 코드를 else 블록으로 래핑하지 않고 작성할 수 있으며 위반된 요구 사항을 처리하는 코드를 요구 사항 옆에 유지할 수 있습니다.
if #available(iOS 10, macOS 10.12, *) {
// Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
} else {
// Fall back to earlier iOS and macOS APIs
}
macOS에서는 macOS 10.12 이상에서만 가능합니다.
if #available(platform name version, ..., *) {
statements to execute if the APIs are available
} else {
fallback statements to execute if the APIs are unavailable
}