https://docs.swift.org/swift-book/documentation/the-swift-programming-language/controlflow
Swift 공식 문서 보면서 내 맘대로 정리
Swift는 다양한 제어흐름 문장을 제공한다.
- 반복을 위한 while
- 조건 분기를 위한 if, guard, switch
- 코드 흐름을 다른 지점으로 전환하는 break, continue
- 배열, 딕셔너리, Range, 문자열 등 시퀀스 반복을 돕는 for-in
- 현재 스코프를 벗어날 때 실행하는 defer
For-In Loops
- Sequence를 반복하여 처리하고 싶을 때 for-in 루프를 사용
- items in an array
- ranges of numbers
- characters in a string
- key-value pairs in a dictionary
[key-value pairs in a dictionary]
- for-in 루프에서 tuple 형태로 (key, value)를 제공
- 딕셔너리 내에서 반환할 때 특정 순서를 보장하지 않는다.
- 보장된 순서를 사용하고 싶다면 직접 구현 또는 swift-collections의 OrderedDictionary 사용을 고려
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
[ranges of numbers]
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
[stride]
- for - in 을 사용할 때 stride(from:to:by), stride(from: through: by:) 를 사용하면 반복을 몇 단계씩 건너뛰고 수행할 수 있다.
- to는 마지막 값 미포함
- through는 마지막 값 포함
- Strideable 을 채택한 타입에 대하여 사용 가능
let minutes = 60
let minuteInterval = 5
for tickMark in stride(from:0, to: minutes, by: minuteInterval){
// 0, 5, 10, ... , 55
}
let hours = 12
let hourInterval = 3
for tickMark in stride(from:3 : through : hours, by : hourInterval){
// 3, 6, 9, 12
}
While Loops
- 조건이 거짓이 될 때까지 반복적으로 명령을 실행하는 루프 구조
- 반복 횟수가 미리 정해져 있지 않은 경우에 적합
- 한 번은
while <#condition#> {
<#statements#>
}
- 조건 없이 명령을 수행하고 그다음부터 조건을 확인하는 repeat-while 문
repeat {
<#statements#>
} while <#condition#>
If
[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."
[더 간결하게 값 반환을 표현하기]
let temperatureInCelsius = 25
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)
- 만약 반환 타입이 옵셔널이라면, Swift는 타입 추론하지 못한다.
- 왜냐면, nil은 Swift의 모든 옵셔널 타입에서 사용할 수 있다.
- 명시적으로 타입을 nil 값 또는 상수 선언부에 제공
let temperatureInCelsius = 25
let weatherAdvice: String? = 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 {
nil
}
// 또는
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 {
nil as String?
}
print(weatherAdvice)
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#>
}
[No Implicit Fallthrough]
- Swift는 C언어와 Obj-C와 다르게 어떤 경우에 만족할 경우 아랫부분을 확인하지 않는다.
- 또한 Switch 문에서 break 문을 요구하지 않는다.
let anotherCharacter = "a"
//잘못된 구문
switch anotherCharacter {
case "a":
case "A":
print("The letter A")
default :
print("Not the letter A")
}
//올바른 구문
switch anotherCharacter {
case "a","A" :
print("The letter A")
default :
print("Not the letter A")
}
[Interval Matching]
- Switch는 어떠한 간격에 대한 조건을 줄 수 있다.
let approximateCount = 62
var naturalCount : String
switch approximateCount {
case 0 :
naturalCount = "no"
case 1..<5 :
naturalCount = "a few"
case 5..<12 :
naturalCount = "serveral"
case 12..<100 :
naturalCount = "dozens of"
case 100..<1000 :
naturalCount = "hundreds of"
default :
naturalCount = "many"
}
[Tuples]
- 여러 값들을 같은 switch 구문에서 사용하고 싶다면 tuple을 사용
- 튜플의 각각의 원소는 다른 조건에 의해 테스트될 수 있음
- (0, 0)은 아래 모든 케이스문에 매칭되는데, Swift에서는 가장 첫 번째 매칭 case 구문을 타고 나머지는 무시된다.
let point = (1,1)
switch point {
case (0,0):
print("origin")
case (_,0):
print("x-axis")
case (0,_):
print("y-axis")
case (-2...2,-2...2):
print("inside the box")
default :
print("outside the box")
}
[Value Bindings]
- switch의 case에서 일시적인 상수나 변수를 선언해서 사용할 수 있다.
let anotherPoint = (2,0)
switch anotherPoint {
case (let x,0):
print("x-axis : (\(x),0)")
case (0, let y):
print("y-axis : (0,\(y)")
case let (x,y):
print("somewhere (\(x),\(y))")
}
- 위 코드에서 let x, let y와 같이 일시적으로 변수를 선언하여 사용할 수 있다.
- 위의 코드에서 let (x,y)는 default와 같은 역할을 수행한다.
[Where]
- switch 구문에서 where 절을 활용하여 추가 조건을 확인할 수 있다
let yetAntoherPoint = (1,-1)
switch letAntoherPoint {
case let (x,y) where x == y:
print("point is on the line y = x")
case let (x,y) where x == -y:
print("point is on the line y = -x")
default:
print("some arbitrary point")
}
Control Transfer Statements
Swift에는 코드 흐름을 제어하여 특정 코드로 이동이나 반복 종료 등 동작을 수행하는 제어 전달 구문이 5가지가 있다.
- continue
- break
- fallthrough
- return
- throw
여기서는 continue, break, fallthrough를 살펴보고 return, throw는 각각 Functions, Error Handling 챕터에서 살펴본다.
Continue
- 현재 반복을 중단하고 다음 반복을 시작
- 루프 안에서 조건을 만족하는 경우, 루프를 빠져나가는 것이 아니라 다음 루프를 건너뛰고 실행되도록 할 때 유용
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"
Break
- 실행 중인 제어 흐름문의 전체 실행을 즉시 종료
- switch 문이나 반복문에서 사용
FallThrough
- switch 문에서 한 케이스를 만족하더라도 다음 케이스의 구문도 수행하도록 하는 예약어
- fallthrough는 case 조건을 확인하지 않고 그냥 다음 case를 실행하게 만든다.
let integerToDescribe = 5
var description = "The number \(integerToDescirbe) is"
switch integerToDescribe {
case 2,3,5,7,11,13,17,19:
print(" a prime number, and also")
fallthrough
default:
description += " an integer"
}
Labeled statements
<#label name#>: while <#condition#> {
<#statements#>
}
- 다른 루프와 조건문 안에 또 다른 조건문을 중첩하여 복잡한 제어흐름 구조를 만들 수 있다.
- 이렇게 만든 루프와 조건문은 break로 조기 종료시킬 수 있다.
- 이 때 종료할 루프와 조건문을 명시적으로 나타내 주는 게 효과적
- 마찬가지로 continue 문도 어떤 루프에 적용되는 것인지 명시하는 것이 유용
var age = 20
var name = "Ick"
checkage: while age < 30 {
if name == "Ick" {
break checkage
} else {
age += 1
}
}
Early Exit
- guard문을 사용하여 조건이 참이어야만 guard 문 뒤의 코드가 실행되도록 요구할 수 있다.
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 else vs if return]
개인적으로 해당 코드의 컨텍스트 및 가독성 여부에 따라 guard else와 if return 사용을 선택하고 있음
guard문 사용을 고려하는 경우
- 현재 스코프에서 반드시 true이어야 다음 코드 라인의 실행이 유의미한 경우
- 옵셔널 바인딩, 초기 값 추출로 이후 코드에서 해당 값이 항상 필요한 경우
if문 사용을 고려하는 경우
- 현재 스코프에서 이후 라인의 진행을 특정 조건에 따라 멈춰야 하는 경우
- 이중 부정으로 조건부의 가독성을 해친다고 판단하는 경우에는 if return문을 선택하기도 함
Deferred Actions
- defer 블록을 사용하면 현재 스코프가 끝날 때 실행될 코드를 작성할 수 있다.
- 함수가 조기 종료되거나, 반복문의 break, 에러가 발생해 throw가 호출되는 경우에도 항상 defer 구문은 수행된다.
- 따라서 메모리 할당 및 해제, 파일 디스크립터 열기 및 닫기, 데이터베이스 트랜잭션 시작 및 종료처럼 쌍을 이루는 작업을 보장하는데 유용
- 두 작업을 코드에서 서로 붙여서 작성할 수 있다는 장점
var score = 1
if score < 10 {
defer {
print(score)
}
score += 5
}
// Prints "6"
- defer문을 여러개 쓰면 역순으로 수행된다.
if score < 10 {
defer {
print(score)
}
defer {
print("The score is:")
}
score += 5
}
// Prints "The score is:"
// Prints "6"
Checking API Availability
- Swift는 API Availability 체크 기능을 내장하고 있다.
- SDK에 맞지 않는 API를 사용하지 않도록 방지
- 컴파일러는 SDK의 가용성 정보를 바탕으로, 프로젝트에 설정된 배포 대상에서 사용하는 API가 모두 가용한 지 검증
- 사용할 수 없는 API를 사용하려 하면 컴파일 에러 발생
- if, guard를 사용하여 조건부 실행이 가능
- 마지막 인수 * 는 필수이고 지정한 최소 배포 버전 이상에서 실행 가능
if #available(iOS 10, macOS 10.12, *){
} else{
}
- unavailable도 함께 사용하면 더 가독성 좋은 코드가 될듯
if #available(iOS 10, *) {
} else {
// Fallback code
}
if #unavailable(iOS 10) {
// Fallback code
}
'iOS > Swift' 카테고리의 다른 글
Swift 공식문서 6. Functions (0) | 2024.09.20 |
---|---|
Swift - In-Out 파라미터 (0) | 2024.09.20 |
Swift - Strideable Protocol (0) | 2024.09.19 |
Swift 공식문서 4. Collection Types (0) | 2024.09.08 |
Swift 공식 문서 3. Strings and Characters (2) (1) | 2024.08.31 |