제어 흐름 (Control Flow) - For-In 루프 (For-In Loops)

00yhsp·2024년 4월 4일

분기, 루프, 이른 종료로 코드를 구성한다.
Swift는 다양한 제어 흐름(control flow) 구문을 제공한다.
이것은 여러번 작업을 수행하는 while 루프를 포함하고
조건에 따라 다르게 실행되는 if, guard, switch 구문과
코드에서 다른 포인트로 실행 플로우를 전달하는 break 와 continue 를 포함한다.
Swift는 배열, 딕셔너리, 범위, 문자열, 그리고 다른 연속적인 것에 대한 반복을 쉽게 만들어 주는 for-in 루프를 제공한다.
Swift는 또한 현재 범위를 벗어날 때 수행되는 코드인 defer 구문을 제공한다.

Swift의 switch 구문은 C와 같은 언어들의 구문보다 훨씬 더 강력하다.
케이스들은 간격 매치, 튜플, 그리고 특정 타입으로의 캐스트를 포함하여 다른 많은 패턴을 비교할 수 있다.
switch 케이스에서 매치된 값은 케이스 문 안에서 사용할 수 있는 임시의 상수 또는 변수로 사용이 가능하고,
복잡한 매칭 조건은 각 케이스에 대해 where 절로 표현될 수 있다.

For-In 루프 (For-In Loops)

배열에 아이템, 범위의 숫자, 또는 문자열에 문자와 같은 연속된 것에 대해 for-in 루프를 사용하여 반복(iterate)할 수 있다.

let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
    print("Hello, \(name)!")
}
// Hello, Anna!
// Hello, Alex!
// Hello, Brian!
// Hello, Jack!

딕셔너리의 키-값 쌍 접근을 위해 반복을 사용할 수도 있다.
딕셔너리의 각 아이템은 딕셔너리가 반복될 때 (key, value) 튜플로 반환되고,
for-in 루프 본문 내에서 사용하기 위해 (key, value) 튜플의 멤버를 명시적으로 이름을 가진 상수로 분해할 수 있다.
아래의 예제에서 딕셔너리의 키는 animalName 상수로 분해되고 딕셔너리의 값은 legCount 상수로 분해된다.

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

Dictionary 의 콘텐츠는 기본적으로 순서가 없으며 반복으로 가져올 아이템에 대한 순서를 보장하지 않는다.
특히 아이템을 딕셔너리에 삽입하는 순서는 아이템이 반복되는 순서를 정의하지 않는다.

숫자 범위에 대해 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

반복되는 시퀀스는 닫힌 범위 연산자(...)를 사용하여 표시되는 1부터 5까지의 숫자 범위이다.
index 의 값은 범위의 첫번째 숫자 (1)로 설정되고 루프 안의 구문이 실행된다.
이 경우 루프는 index 의 현재 값을 5배 하여 출력하는 하나의 구문만 포함한다.
구문이 실행된 후에 index 의 값은 범위의 두번째 값 (2)로 업데이트 되고 print(_:separator:terminator:) 함수가 다시 호출된다.
이 프로세스는 범위의 끝에 도달할 때까지 계속된다.

위의 예제에서 index는 루프의 각 반복이 시작할 때 자동으로 설정되는 값인 상수이다.
따라서 index를 사용하기 전 선언할 필요가 없으며, let 선언 키워드가 필요 없이 루프 선언에 포함되어 암시적으로 선언된다.

시퀀스로부터 각 값이 필요하지 않으면 변수 이름의 위치에 언더바를 사용하여 값을 무시할 수 있다.

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"

위의 예는 한 숫자의 값을 다른 숫자의 제곱으로 계산한다(이 경우 3 에서 10 제곱).
1 로 시작하고 10 으로 끝나는 닫힌 범위를 사용하여 시작값 1 (즉, 3 의 0 제곱)에 3 을 10 번 곱한다.
이 계산에서 루프의 각 카운터 값은 불필요하다.
즉 이 코드는 간단하게 올바른 숫자만큼 실행되며, 루프 변수 위치에 사용된 언더바 문자 (_)는 각 값을 무시하고 루프의 각 반복동안 현재 값에 접근하는 것을 제공하지 않는다.

어떤 상황에선 양 끝점을 포함하는 닫힌 범위를 사용하지 않을 수 있다.
시계 페이스에 매 분마다 눈금을 그리는 것을 생각해 보면, 0 분을 시작으로 60 개의 눈금을 그려야 한다.
이럴 경우 반열림 범위 연산자 (..<)를 사용하여 가장 최소 값은 포함하지만 최대 값은 포함되지 않게 사용할 수 있다.

let minutes = 60
for tickMark in 0..<minutes {
    // render the tick mark each minute (60 times)
}

어떤 사용자는 UI에 더 적은 눈금을 원할 수도 있다.
매 5분마다 눈금을 그리기 원할 수 있다.
원하지 않는 눈금을 건너뛰기 위해 stride(from:to:by:) 함수를 사용할 수 있다.

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:through:by:) 사용하여 닫힌 범위도 가능하다.

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)
}

위의 예제는 범위, 배열, 딕셔너리, 그리고 문자열을 조회하기 위해 for-in 루프를 사용한다.
자체 클래스와 콜렉션 타입을 포함하여 모든 콜렉션을 조회하기 위해 시퀀스 프로토콜을 준수하는 한 이 구문을 사용할 수 있다.

profile
iOS Dev

0개의 댓글