
조건이 포함하는 코드 기반의 다른 조각을 실행할 때 유용한 경우가 있다.
에러가 발생하거나 값이 너무 크거나 작을 때 메세지를 출력하려고 할 때 코드의 별도의 부분을 실행하고 싶을 수 있다.
이러한 동작을 위해 코드 조건부의 부분을 만들어야 한다.
Swift는 코드에 조건부를 추가하는 방법은 if 구문과 switch 구문 2가지를 제공한다.
일반적으로 if 구문은 가능한 결과가 적은 간단한 조건에 적합하다.
switch 구문은 가능한 결과가 여러개이며 더 복잡한 조건에 적합하고 실행해야 할 적절한 코드 분기를 선택해야 하는 패턴 매칭 상태에 유용하다.
가장 간단한 형식으로 if 구문은 단일 if 조건을 갖는다.
조건이 true 일 경우에만 구문을 실행한다.
var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
}
// Prints "It's very cold. Consider wearing a scarf."
위 예제는 기온이 화씨 32도 보다 작거나 같은지 확인한다.
만약 화씨 32도 보다 작거나 같으면 메세지가 출력된다.
반대는 메세지가 출력되지 않으며 코드는 if 구문의 닫힘 중괄호 이후를 계속 실행한다.
if 구문은 if 조건이 false 일 때 그 밖의 다른 구문을 제공할 수 있다.
이 구문은 else 키워드로 표기한다.
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."
2개의 중괄호 중 하나는 항상 실행된다.
기온이 증가하여 화씨 40 도를 가지므로 더이상 추워서 스카프를 해야 한다고 충고하지 않으며 else 구문이 실행된다.
추가 절을 고려하기 위해 여러 if 구문을 연결할 수 있다.
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."
여기 if 구문은 특정 따뜻한 기온에 응답하기 위해 추가되었다.
마지막 else 절은 남아있고 어떤 기온이 너무 따뜻하거나 너무 춥지 않을 경우에 응답을 출력한다.
그러나 마지막 else 절은 옵셔널이고 이 조건이 완벽하게 필요가 없으면 제외할 수 있다.
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.")
}
기온이 너무 춥지도 따뜻하지도 않아 if 또는 else if 조건에 포함되지 않으므로 아무런 메세지가 출력되지 않는다.
Swift 는 값을 설정할 때 사용할 수 있는 if 의 짧은 구문을 제공한다. 예를 들어, 아래 코드와 같다.
let temperatureInCelsius = 25
let weatherAdvice: String
if temperatureInCelsius <= 0 {
weatherAdvice = "It's very cold. Consider wearing a scarf."
} else if temperatureInCelsius >= 30 {
weatherAdvice = "It's really warm. Don't forget to wear sunscreen."
} else {
weatherAdvice = "It's not that cold. Wear a T-shirt."
}
print(weatherAdvice)
// Prints "It's not that cold. Wear a T-shirt."
여기서, 각 분기는 if 구문 이후에 출력되는 weatherAdvice 상수에 값을 설정한다.
if 표현식을 다른 표현을 사용하여 더 간결하게 코드를 작성할 수 있다.
let weatherAdvice = if temperatureInCelsius <= 0 {
"It's very cold. Consider wearing a scarf."
} else if temperatureInCelsius >= 30 {
"It's really warm. Don't forget to wear sunscreen."
} else {
"It's not that cold. Wear a T-shirt."
}
print(weatherAdvice)
// Prints "It's not that cold. Wear a T-shirt."
이 if 표현식에서 각 분기는 하나의 값을 포함한다.
분기의 조건이 참이면, 값은 weatherAdvice 에 할당되고 if 표현식 전체에 대한 값으로 사용된다.
모든 if 분기는 else if 분기 또는 else 분기를 가지고 있어 분기 중 하나에 항상 일치하고 if 표현식이 어떤 조건이 참인지 상관없이 값을 항상 생성한다.
할당 구문은 if 표현식 바깥에서 시작하므로 각 구문안에 weatherAdvice = 를 반복할 필요가 없다.
대신에 if 표현식의 각 구문은 weatherAdvice 의 값을 세가지 중 하나로 생성하고 할당한다.
if 표현식의 모든 구문은 동일한 타입의 값을 포함해야 한다.
Swift 는 각 분기의 타입을 개별적으로 확인하기 때문에 둘 이상의 타입으로 사용될 수 있는 nil 과 같은 값은 Swift 가 if 표현식의 타입을 자동으로 결정하는 것을 방지한다. 대신에 타입을 명시적으로 지정해야 한다.
let freezeWarning: String? = if temperatureInCelsius <= 0 {
"It's below freezing. Watch for ice!"
} else {
nil
}
위의 코드에서 if 표현식 중 하나의 분기는 문자열 값을 가지고 다른 분기는 nil 값을 가진다.
nil 값은 모든 옵셔널 타입의 값으로 사용될 수 있으므로 타입 명시 (Type Annotations) 에서 설명했듯이 freezeWarning 은 옵셔널 문자열이라고 명시적으로 작성되어야 한다.
타입 정보를 제공하기 위한 다른 방법은 freezeWarning 에 대한 타입을 명시적으로 제공하는 대신에 nil 에 대한 타입을 명시적으로 제공하는 것이다.
let freezeWarning = if temperatureInCelsius <= 0 {
"It's below freezing. Watch for ice!"
} else {
nil as String?
}
if 표현식은 에러를 전파하거나 반환하지 않는 fatalError(_:file:line:)과 같은 함수를 호출하여 예기치 않은 실패를 나타낼 수 있다.
let weatherAdvice = if temperatureInCelsius > 100 {
throw TemperatureError.boiling
} else {
"It's a reasonable temperature."
}
이 예제에서 if 표현식은 물의 끓는점인 100℃ 보다 높은지 확인한다.
이렇게 뜨거운 온도는 텍스트의 요약을 반환하는 대신에 .boiling 에러를 발생시킨다.
if 표현식은 에러를 발생할 수 있지만 try 를 전에 작성하지 않는다.
위의 예제에서와 같이 할당의 오른편으로 if 표현식을 사용하는 것 외에 함수 또는 클로저가 반환하는 값으로도 사용할 수 있다.
switch 구문은 값을 고려하고 가능한 여러개의 일치 패턴과 비교한다.
그런 다음 첫번째로 일치하는 패턴을 기반으로 적절한 코드 블럭을 실행한다.
switch 구문은 여러 가능한 상태에 응답하기 위해 if 구문의 대체 구문으로 제공한다.
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#>
}
모든 switch 구문은 각각 case 키워드로 시작하는 여러개의 케이스 로 구성되어 있다.
특정 값과 비교하는 것 외에도 Swift는 각 케이스에 대해 더 복잡한 일치 패턴을 지정하는 여러가지 방법을 제공한다.
if 구문의 본문과 같이 각 case 는 코드 실행 부분이 분리되어 있다.
switch 구문은 실행 될 부분을 선택한다. 이 절차를 값의 스위칭 (switching) 이라 한다.
모든 switch 구문은 완벽해야 한다.
이것은 고려중인 타입의 가능한 모든 값은 switch 케이스 중 하나와 일치해야 한다는 것을 의미한다.
가능한 모든 값에 대한 케이스를 제공하는 것이 적절하지 않은 경우 명시적으로 해결되지 않은 모든 값을 포함하도록 기본 케이스를 정의할 수 있다.
기본 케이스는 default 키워드로 나타내고 항상 마지막에 위치한다.
let someCharacter: Character = "z"
switch someCharacter {
case "a":
print("The first letter of the Latin alphabet")
case "z":
print("The last letter of the Latin alphabet")
default:
print("Some other character")
}
// Prints "The last letter of the Latin alphabet"
switch 구문의 첫번째 케이스는 영어 알파벳의 첫번째 문자인 a 와 일치하고 두번째 케이스는 마지막 문자인 z 와 일치한다.
switch 는 모든 알파벳 문자 뿐만 아니라 모든 가능한 문자에 대한 케이스를 가지고 있어야 하므로 이 switch 구문은 a 와 z 을 제외한 다른 모든 문자는 default 케이스를 사용한다.
이렇게 함으로 switch 구문은 완벽하다는 것을 보장한다.
if 구문과 같이 switch 구문도 아래와 같은 표현식 형태를 가지고 있다.
let anotherCharacter: Character = "a"
let message = switch anotherCharacter {
case "a":
"The first letter of the Latin alphabet"
case "z":
"The last letter of the Latin alphabet"
default:
"Some other character"
}
print(message)
// Prints "The first letter of the Latin alphabet"
이 예제에서 switch 표현식에 각 케이스는 anotherCharacter 와 동일한 케이스일 때 사용될 message 에 대한 값을 포함한다.
switch 는 항상 동일한 케이스가 존재하기 때문에 값은 항상 할당된다.
if 표현식과 마찬가지로 주어진 케이스에 대해 값을 제공하는 대신에 에러를 발생시키거나 반환되지 않는 fatalError(_:file:line:) 과 같은 함수를 호출할 수 있다.
위의 예제에서와 같이 할당의 오른편에 있는 switch 표현식을 함수 또는 클로저가 반환하는 값으로 사용할 수 있다.
C와 Objective-C의 switch 구문과 다르게 Swift의 switch 구문은 기본적으로 각 케이스의 바닥에서 다음 케이스로 바로 실행되지 않는다
명시적으로 break 구문 요청 없이 처음 일치하는 switch 케이스가 완료되자마자 switch 구문 전체가 끝난다.
이러한 점은 switch 구문을 더 안전하고 C의 switch 구문보다 사용하기 쉽게 해주고 실수로 switch 케이스가 하나 이상 실행되는 것을 피할 수 있습니다.
Note:
Swift에서 break 는 요구되지 않지만 특정 케이스를 무시하거나 일치하는 케이스의 실행이 완료되기 전에 빠져나와야 할 경우 break 구문을 사용할 수 있다.
각 케이스의 본문은 반드시 적어도 하나의 실행가능한 구문이 포함되어야 합니다. 아래의 코드는 첫번째 케이스가 비어 있으므로 유효하지 않다.
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.
C의 switch 구문과 다르게 이 switch 구문은 "a" 와 "A" 둘 다 일치하지 않는다.
case "a": 에 어떠한 실행가능한 구문이 없기 때문에 컴파일 에러가 발생한다.
이 접근 방식은 한 케이스에서 다른 케이스로의 우발적인 실행을 방지하고 의도를 더 명확하게 하고 안전한 코드를 만든다.
"a" 와 "A" 모두 일치하는 단일 케이스의 switch 를 만드려면 두 값을 콤마로 구분하여 하나로 결합하여 구성한다.
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
print("The letter A")
default:
print("Not the letter A")
}
// Prints "The letter A"
읽기 쉽게 하기위해 합성 케이스는 여러줄로 작성할 수도 있다.
Note:
특정 switch 케이스에 끝에서 명시적으로 다음 케이스로 떨어뜨리려면 fallthrough 키워드를 사용한다.
switch 케이스 안에 값은 간격을 포함하여 확인할 수 있다.
이 예제는 숫자 간격을 사용하여 모든 크기의 숫자에 대한 자연어 갯수를 제공한다.
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."
위의 예제에서 approximateCount 는 switch 구문에서 판단된다.
각 case 는 숫자 값 또는 간격을 비교한다.
approximateCount 의 값은 12와 100 사이에 속하므로 naturalCount 는 "dozens of" 값이 할당되고 switch 구문을 빠져나온다.
같은 switch 구문에 여러 값인 튜플을 사용할 수 있다.
튜플의 각 요소는 다른 값 또는 값의 간격을 판단할 수 있다.
가능한 어떠한 값도 일치하도록 와일드카드 패턴 (wildcard pattern)으로 알려진 언더바 문자 (_)를 사용할 수 있다.
아래 예제는 타입 (Int, Int) 의 간단한 튜플로 표현된 (x, y) 포인트를 가지며 그래프에서 분류한다.
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"

switch 구문은 점이 원점 (0, 0) 인지, 빨간색 x축 위에 있는지, 초록색 y축 위에 있는지, 원점이 중심인 파란색 4 x 4 박스 내부에 있는지 외부에 있는지 판단한다.
C와 다르게 Swift는 여러 switch 케이스가 같은 값 또는 값들인지 고려하는 것이 가능하다.
사실 점 (0, 0)은 이 예제의 모든 4개의 케이스에 일치한다.
그러나 여러개가 일치할 수 있다면 첫번째 일치하는 케이스가 항상 사용된다.
점 (0, 0)은 첫번째 case (0, 0) 와 일치하고 다른 모든 케이스는 무시된다.
switch 케이스는 일치하는 값 또는 값들을 임시적 상수 또는 변수로 이름을 가질 수 있으며 케이스 본문 안에서 사용할 수 있다.
같은 케이스의 본문 내부에서 임시적 상수 또는 변수로 바인드되기 때문에 이러한 동작을 값 바인딩(Value Binding)이라 한다.
아래 예제는 튜플의 타입 (Int, Int)로 표현된 점 (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))")
}
// Prints "on the x-axis with an x value of 2"

이 switch 구문은 점이 빨간색인 x축에 있는지, 초록색인 y축에 있는지, 또는 다른 곳 (축 위가 아닌)에 있는지 판단한다.
이 3개의 switch 케이스는 자리 상수 x 와 y 를 선언하며 anotherPoint 에서 임시적으로 하나 또는 2개의 튜플 값을 받는다.
첫번째 케이스인 case (let x, 0) 는 y 점 값이 0 이고 x 점 값은 임시적 상수 x 에 할당한 것과 일치한다.
비슷하게 두번째 케이스 case (0, let y) 는 x 점 값이 0 이고 y 점 값은 임시적 상수 y 에 할당한 것과 일치한다.
임시적 상수가 선언된 후에 케이스의 코드 블럭 안에서 사용될 수 있다. 여기서는 점을 분리해 출력한다.
이 switch 구문은 default 케이스를 가지고 있지 않다.
마지막 케이스 case let (x, y) 는 어떠한 값도 일치할 수 있는 2개의 상수를 가지는 튜플로 선언한다. anotherPoint 는 2개 값의 튜플이기 때문에 가능한 남아있는 모든 케이스와 일치하며 switch 구문을 완벽하게 하기위해 default 케이스가 필요치 않다.
switch 케이스는 추가 조건으로 where 절을 사용할 수 있다.
아래 예제는 그래프에 (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")
}
// Prints "(1, -1) is on the line x == -y"

switch 구문은 x == y 인 초록색 대각선 위에 있는지, x == -y 인 보라색 대각선 위에 있거나 아니면 그 외에 위치하는지 판단한다.
3개의 switch 케이스는 yetAnotherPoint 에서 임시적으로 2개의 튜플 값을 가지는 x 와 y 상수를 선언한다.
이 상수는 다이나믹 필터를 생성하기 위해 where 에 부분적으로 사용된다.
switch 케이스는 where 절의 조건이 true 일 때만 point 의 현재 값이 일치한다.
이전 예제와 마찬가지로 마지막 케이스는 가능한 남아있는 값과 모두 일치하므로 switch 구문을 완벽하게 하기 위해 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")
}
// Prints "e is a vowel"
switch 구문의 첫번째 케이스는 영어의 5개의 소문자 모음이 일치한다.
비슷하게 두번째 케이스는 모든 영어 소문자 자음이 일치한다.
마지막으로 default 케이스는 다른 어떠한 문자와 일치한다.
혼합 케이스 (Compound cases)는 값 바인딩을 포함할 수도 있다.
혼합 케이스의 모든 패턴은 값 바인딩의 같은 집합을 포함해야 하고 각 바인딩은 혼합 케이스에 모든 패턴으로 부터 같은 타입의 값을 얻어야 한다.
혼합 케이스 부분이 일치하는 것과 상관없이 케이스의 본문에 코드는 바인딩을 위해 값에 항상 접근할 수 있고 값은 항상 같은 타입을 가진다.
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"
위의 case 는 2개의 패턴을 가지고 있다.
(let distance, 0) 은 x축 위의 점과 일치하고 (0, let distance) 는 y축 위의 점과 일치한다.
두 패턴 모두 distance 바인딩을 포함하고 distance 는 두 패턴에서 정수이다.
즉, case 의 본문 안에 코드는 항상 distance 로 값에 접근할 수 있다는 의미이다.