Search

[Swift 공식 문서] 5. Control Flow

부제
카테고리
Swift
세부 카테고리
공식문서 번역
Combine 카테고리
최종편집일
2022/07/16 15:22
작성중
관련된 포스팅
생성 일시
2022/07/16 14:47
태그
Swift 다양한 control flow 구문을 제공합니다. while 문 같은 경우는 특정 task 를 여러번 반복할 수 있게 해주고, if guard swiftch 문 같은 경우에는 특정 상황에 기반해 코드의 여러 분기점을 만들어 실행하게 해줍니다.
또한 breakcontinue 키워드는 실행의 흐름을 코드의 드른 부분으로 옮겨줍니다.
for in loop 에서는 어레이, 딕셔너리, range, string 그리고 여러 열거 타입들을 순회 할수 있습니다.
switch 문은 C 언와 같은 다른 언어들과 비교될 정도로 강력한 기능을 가집니다. Case 들은 다양한 패턴과 매칭됩니다.

For-In Loops

열거형 타입을 순회하기 위해서는 for in 문을 사용합니다.
let names = ["Anna", "Alex", "Brian", "Jack"] for name in names { print("Hello, \(name)!") } // Hello, Anna! // Hello, Alex! // Hello, Brian! // Hello, Jack!
Swift
복사
어레이의 순환
딕셔너리 또한 순회가 가능합니다. 딕셔너리의 가각의 항목은 (key, value) 튜플로써 반환되며, 이를 decompose 하여 for in loop 안에서 사용이 가능합니다.
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
Swift
복사
딕셔너리의 순회
딕셔너리 같은 경우 순서가 없기 때문에 재실 행시 같은 순서로 실행될 것이라는 보장을 하지 않습니다.
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
Swift
복사
numeric ranges 또한 순회가 가능합니다.
범위 연산자 ... 를 활용하여 특정 범위의 정수를 순회할 수 있습니다.
위의 예시에서 알 수 있듯이for in loop 에서
1.
index 값은 상수로 선언되며 코드가 반복될 때 마다 재 생성 됩니다. 또한
2.
index 는 미리 선언하지 않아도 사용이 가능합니다.
(loop 문 내에서 암묵적으로 선언 됩니다.) 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"
Swift
복사
half-open 연산자를 사용해서 마지막 값을 제외하고 순회할 수 있습니다.
let minutes = 60 for tickMark in 0..<minutes { // render the tick mark each minute (60 times) }
Swift
복사
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) }
Swift
복사
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) }
Swift
복사
Seaquence 프로토콜을 준수하는 모든 타입은 for - in loop 내에서 순회가 가능합니다.

While Loops

while loop 는 조건이 false 가 될 때까지 반복을 수행합니다. 이러한 종류의 loop 는 숫자 타입의 순회 사용시 적합합니다. Swift 는 두가지 형태의 while loop 를 제공합니다.
while : loop 의 시작 부분에서 조건을 검사합니다.
repeat-while : loop 의 마지막 부분에서 조건을 검사합니다.

While

while loop 는 하나의 조건을 평가하면서 시작됩니다. 조건이 true 면 내부의 코드블럭이 실행되고 false 가 될 때까지 이 코드블럭을 반복적으로 수행합니다.
while condition { statements }
Swift
복사

Repeat-While

while loop 의 변형형으로, 먼저 loop 블록을 한번 실행한뒤에 loop 의 조건을 검사하고, 조건이 참이면 loop 를 한번 더 반복한다.
repeat { statements } while condition
Swift
복사

Conditional Statesments

조건문을 활용해 상황에 따라 다른 코드가 실행되도록 할 수 있습니다. Swift 에는 code 를 분기할 수 있는 두가지 방법인 switchif 문을 제공합니다.
일반적으로 if 문은 단순한 조건을 판단하기에 적합하고, switch 문은 만은 가능성이 존재할 때 사용됩니다.

If

아래는 if 문의 가장 간단한 형태입니다
var temperatureInFahrenheit = 30 if temperatureInFahrenheit <= 32 { // 조건이 참이면 print("It's very cold. Consider wearing a scarf.") //출력 } // Prints "It's very cold. Consider wearing a scarf."
Swift
복사
조건이 참이면 중괄호 안의 코드가 실행됩니다.
아래는 else 키워드를 사용한 코드 예제입니다.
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."
Swift
복사
조건은 항상 참 또는 거짓이므로 두 코드블럭 중 하나는 무조건 실행됩니다.
여러개의 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."
Swift
복사
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.") }
Swift
복사

Switch

switch 문은 하나의 값을 여러개의 가능한 패턴과 비교합니다. 첫번째로 일치하는 적절한 코드 블럭을 실행하게 됩니다. 많은 잠재적 상황이 존재할 시 if 문 대신 사용하세요
아래는 switch 문의 기본 사용법입니다.
switch some valueToConsider { case value1: //valueToConsider 이 value1 값과 같을 때 실행되는 블럭 case value2, value3: //valueToConsider 이 value1 값과 같을 때 실행되는 블럭 default: //valueToConsider 이 value1 값과 같을 때 실행되는 블럭 }
Swift
복사
switch 문은 여러가지 가능한 경우의 수를 case 키워드로 정의합니다.
Swift 에서는 더 복잡한 패턴을 다룰 수 있도록 여러가지 방안을 제공합니다.
switch 문에서는 반드시 발생가능한 모든 case 를 다루어야합니다.
만약 모든 case 가 복잡한 패턴을 가진다면 default 키워드를 사용하여서 나머지 경우의 수들을 한번에 다룰 수 있습니다. default 키워드는 반드시 맨 마지막에 위치해야합니다.
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
복사

No Implicit Fallthrough

C 와 Objective C 에서의 switch 문은 기본적으로 모든 case 들을 하나씩 검사합니다. 하지만 Swift 의 switch 문은
그대신 만약 첫번째로 일치하는 case 가 존재한다면 switch 문을 종료합니다.
따라서 단 하나의 case 문만이 실행됩니다.
break 키워드를 사용해서 특정 case 에 대해서 해당 case 의 코드 실행을 종료, switch 문을 탈출할 수 있습니다.
각각의 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.
Swift
복사
위 코드같은 경우 아래와 같이 고쳐쓸 수 있습니다.
let anotherCharacter: Character = "a" switch anotherCharacter { case "a", "A": // 여러개의 케이스를 묶을 수 있음 print("The letter A") default: print("Not the letter A") } // Prints "The letter A"
Swift
복사
이렇게 결합된 case 들은 가독성을 위해 여러줄로 작성될 수 있습니다.
fallthrough 키워드를 사용해서 특정 case 에서 일치한다 해도 모든 case 들과 비교를 진행합니다.

Interval Matiching

switch 문안의 case 들은 구간내의 포함여부를 체크할 수 있습니다.
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."
Swift
복사

Tuples

Switch 문에서 다수의 값을 한번에 비교하기 위해 tuple 을 사용할 수 있습니다. 각각의 튜플 원소들은 다른 구간, 다른 값들의 구간에 대해 test 를 받게 됩니다. 대신 언더스코어를 활용해서 특정 원소의 비교를 무시할 수 있습니다.
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") }
Swift
복사
만약 위 코드에서 somePoint(0,0) 에 해당한다면 (0,0)아래의 case 들은 모두 무시됩니다.

Value Bindings

switch case 에서 임시 값을 상수 또는 변수에 저장할 수 있습니다. 이를 value binding 이라고 합니다. 이 임시 값은 case 문 내에서 임시로 사용되며, 그 case 문이 종료되면 유효하지 않습니다,
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"
Swift
복사
이 swtich 문에는 default 케이스가 정의되지 않았습니다. anotherPoint 가 항상 두개의 값을 가지는 튜플이므로 마지막 case 에 항상 대응 되므로 default case 가 필요하지 않습니다.

Where

Where 절을 사용해서 추가 조건을 검사할 수 있습니다. 앞서 논의한 임시 값을 활용해 추가조건을 생성할 수 있습니다. where 절의 조건이 참이어야지만 case 문이 실행됩니다.
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"
Swift
복사
마찬가지로 마지막 case 가 모든 가능한 상황을 포괄하므로 default case 가 필요없습니다.

Compound Cases

콤마를 사용해 여러개의 패턴들을 하나의 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) isn't a vowel or a consonant") } // Prints "e is a vowel"
Swift
복사
value binding 을 포함하는 case 문에도 마찬가지로 콤마를 활용해 여러개의 패턴에 대한 동일한 로직을 작성할 수 있습니다.
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"
Swift
복사

Control Transfer Statements

Control Transfer 문은 코드의 실행 순서를 바꿀 수 있도록 합니다.
5개의 Control Transfer 문이 존재합니다.
continue
break
fallthrough
return
throw

Continue

continue 문은 현재 코드의 동작을 멈추고 실행 순서를 다음 loop 로 옮기는 것을 의미합니다.
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"
Swift
복사

Break

break 문은 전체 control flow 문을 즉시 종료합니다. switch 나 loop 문에서 사용이 가능합니다.

Break in a Loop Statement

loop 의 실행을 즉시 종료하고 loop 의 다음으로 코드의 실행순서를 변경합니다.
어떠한 현재 loop 의 코드도 실행되지않으며 다음 loop 또한 실행되지 않습니다.

Break in a Switch Statement

switch 문 내에서 사용되면 switch 문의 실행을 즉시 종료하고, switch 문의 중괄호 다음으로 코드의 실행순서를 옮깁니다.
여러개의 case 들을 무시할 수 있도록 합니다. Switch 문에서는 빈 case 들을 허용 하지 않으나 ,, 몇몇의 case 에 대해서는 break 문을 사용함으로써 동작을 구현하지 않을 수 있습니다.
즉 무시하고 싶은 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."
Swift
복사

Fallthough

Swift 에서 switch 문은 특정 case 와 일치하게 되면 나머지 case 들을 검사하지 않습니다. 이러한 기본적인 셋팅을 바꾸어 일치하더라도 나머지 case 들에 대해서 검사를 진행하려면 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) // Prints "The number 5 is a prime number, and also an integer."
Swift
복사

Labeled Statements

루프 또는 여러 조건문들이 중첩되게 되면 위에서 언급한 control transfer 문들이 어떤 루프에 영향을 미치는 지가 불분명 할 수 있습니다.
따라서 이를 명시할 수 있습니다.
1.
먼저 loop 에 이름을 붙여야합니다.
2.
control transfer 문과 함께 loop 의 이름을 명시합니다.
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 // switch 문이 아닌 while 문을종료 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!")
Swift
복사
이처럼 변경하고자 하는 control flow 의 대상을 명확히 할 수 있습니다.
위 예시에서 loop 는 while 문 하나이므로 continue 에 한해서는 label 을 작성하지 않아도 그 대상이 명확하기 때문에 사용할 필요가 없습니다.

Early Exit

guard 문을 활용하면 if 문 처럼 특정 코드에 대한 실행 여부를 Boolean 표현식 에 기반해 결정할 수 있습니다.
함수가 실행되기 위한 선행조건을 만족하는 지를 확인하는데 자주 사용됩니다.
func greet(person: [String: String]) { guard let name = person["name"] else { return // name 의 key 값이 존재하지 않는다면 함수 실행 종료 } 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."
Swift
복사
guard 문은 옵셔널 바인딩을 통해 값을 name 에 할당합니다.
만약 값이 존재하지 않는다면(nil) else 이후의 코드블럭이 실행됩니다.
여기서는 return 이 실행되며, return 대신 다른 control transfer 문들 또한 실행이 가능합니다(breakcontinue, or throw)
gaurd 문을 코드 실행에 필요한 선행 조건으로 사용한다면 if 문 보다, 코드의 가독성이 증가합니다.

Checking API Availability

Swift 에는 API 의 사용 가능성을 점검하기 위한 빌트인 기능이 존재합니다. 이 기능은 주어진 target 의 배치에 있어서 API 의 사용이 불가능할 때, 실수로 API 를 사용하지 않도록 보장해줍니다.
컴파일러는 SDK 의 내의 사용가능성에 대한 정보를 사용하여 특정 코드의 배치 내에서 API 가 사용 가능한지를 확인합니다. 만약 API 가 사용가능하지 않다면 Swift 는 컴파일 에러를 발생시킵니다.
if 또는 guard 문에 availability condition 을 사용할 수 있습니다. API 가 사용가능한지에 따라 코드의 실행여부를 결정할 수 있습니다. 또한 컴파일러는 availability condition 으로부터 API 의 사용가능성 에 대한 정보를 얻어와 사용할 수 있습니다.
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 }
Swift
복사
if #available 문을 사용해 특정 코드가 특정 플랫폼의 버전 이상에서만 사용가능하도록 구성할 수 있습니다.
#available은 여러 플랫폼에서 서로 다른 논리 처리를 결정하기 위해서 if 또는 guard문과 같이 사용됩니다.
즉, Bool을 반환하는 런타임 검사입니다.
주의할 점은, 해당 버전을 포함하여 그 이상의 버전"인지를 확인합니다.