Swift study - Control Flow

rbw·2022년 3월 4일
0

swift-study

목록 보기
9/17
post-thumbnail

Swift - Control Flow

스위프트는 다양한 제어 흐름 문을 제공한다. 이는 여러번 반복을 수행하는 while 문을 포함하고, 특정 조건을 따라 코드에 다른 분기를 실행하는 if, guard, switch 문도 제공하고, 코드에 다른 부분으로 실행 흐름을 전환하게 해주는 break, continue 문도 제공한다.

스위프트는 또한 배열, 딕셔너리, 범위, 문자열과 다른 순서들의 반복을 편하게 만들어 주는 for-in 문도 제공한다.

스위프트의 switch 문은 많은 유사 C언어의 구문들에 비해 상당히 강력하다. 케이스는 간격 일치, 튜플, 특정 유형으로의 캐스팅을 포함하여 여러 다른 패턴을 일치하게 할 수 있다. switch 케이스의 매치된 값은 케이스 내부에서 사용되기 위해 임시 상수나 변수에 바인딩 되어 사용이 가능하고, 복잡한 매칭 조건은 각 케이스에 where절과 함께 표현할 수 있다.

interval matches(간격 일치) : 스위프트의 범위 연산자가 유효한지 확인하는것. 예로 case 1701...1800 : 로 명시하여 분기를 나눌 수 있다.

For-In Loops (For-In 루프)

배열, 숫자의 범위, 문자열 안의 문자들과 같은 요소들은 for-in 루프를 사용해서 반복 할 수 있다.

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

// 딕셔너리의 for-in 사용 예시
// 임시 상수나 변수로 for-in 문 내부에서 사용이 가능하다
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-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

위의 숫자 범위의 예에서 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"

위 계산에서 각 반복마다 카운터 값은 필요하지 않다. 코드는 단순히 정확한 숫자만큼의 반복을 실행한다.

여러 상황에서, 마지막 범위를 포함하고 싶지 않을 수가 있다. 범위 연산자에 내용에서 배운 ..< 로 표현을 하면 마지막 포인트를 포함하지 않고 반복을 종료한다.

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

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

위의 예시들은 숫자 범위, 배열, 딕셔너리, 문자열의 for-in문의 사용 예시들이다. 하지만 어떤 컬렉션에도 이 구문을 사용할 수 있으며, Sequence 프로토콜을 준수하는 한 자신이 만든 클래스나 컬렉션 타입들에서도 사용이 가능하다.

While Loops (while 루프)

while 루프는 조건이 false가 되기전 까지 반복을 수행한다. 첫 반복이 시작되기 전에 반복 회수를 모를 때 가장 잘 사용하는 반복의 종류이다. 스위프트는 두가지 while 루프를 제공한다.

  • while은 각 루프가 시작할때 조건을 평가한다.
  • repeat-while은 루프가 종료될때 조건을 평가한다.

While

While문은 단일 조건을 평가함으로써 시작한다. 만약 조건이 true라면 조건이 false가 될 때 까지 지정된 반복문을 반복한다.

snake game

위 게임으로 반복문을 설명. 뱀의 머리에서 멈춘다면 그림만큼 내려가고, 사다리 시작 부분에서 멈춘다면 그 만큼 위로 올라가는 게임이다. 주사위를 이용하고 0 에서 시작한다.

// 0 부터 시작하므로 총 26개의 0인 Int로 배열이 구성된다.
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

꼭 필요하지는 않지만, 코드의 가독성을 위해 십의 자리보다 작은 숫자에는 0을 붙여서 단항 연산자와 함께 표현을 하였다.

var square = 0
var diceRoll = 0
while square < finalSquare {
    // roll the dice
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    // 주사위 만큼 이동
    square += diceRoll
    if square < board.count {
        // 사다리나, 뱀 조건을 체크
        square += board[square]
    }
}
print("Game over!")

위 코드는 주사위 값을 간단히 표현 했으며, 원래는 랜덤 숫자로 표현한다. diceRoll 이 7이 된다면 1~6 범위보다 커지므로 1로 만들어 주는 조건도 포함.

주사위를 굴린 후 주사위 수 만큼 플레이어는 위치를 움직인다. 25 이상으로 넘어간다면 게임은 종료된다. 이 시나리오를 대비하기 위해 코드에서는 square 가 배열이 count 프로퍼티보다 작은지 체크한다. square가 유효하다면 board[square] 안의 값을 square에 더해 저장한다.

NOTE

만약 위 조건이 수행되지 않는다면 board[square]은 배열 밖의 값에 접근을 시도할 수도 있다. 이 경우는 런타임 에러를 발생 시킨다.

현재 while 루프의 실행이 종료된 후, 다음 루프가 다시 실행을 해야만 하는지 조건이 체크된다. 25 보다 넘어버린다면, 루프 조건은 false로 평가하고 게임은 끝이난다.

위 케이스에서 while 루프는 적절하다. while 루프의 시작될 때 게임의 길이가 명확하지 않기 때문이다. 대신 루프는 특정 조건이 만족할때 까지 실행한다.

Repeat-While

while 루프에 다른 종류로 repeat-while 이 존재한다. 이는 조건을 고려하기 전에 한 번 실행을 하고, 조건이 false 일때 까지 반복한다.

NOTE

스위프트의 repeat-while 루프는 다른 언어의 do-while 루프와 비슷하다.

위의 게임을 repeat-while 루프로 설명하는 예시

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

repeat {
    // 먼저 사다리, 뱀 부분을 더해준다.
    // 보드의 어떤 사다리도 플레이어를 25칸으로 바로 이동시키지 않으므로 이렇게 작성하는 것이 안전하다.
    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!")

위 코드의 square < finalSquare 은 첫 실행이 종료되기 전까지 평가되지 않는다. 위 구조는 이전의 while 구조보다 이 게임에 더 적합하다. square += board[square]squareboard 위에 있는 조건이 통과하자마자 실행이 된다. 이 동작은 앞의 while 루프 버전에서 볼 수 있는 배열의 경계 검사의 필요성을 제거한다.

Conditional Statements (조건문)

이는 특정 조건에 따라 코드의 조건을 다르게 실행하는데 유용하다. 에러를 발생할 때 추가 코드를 실행하거나, 값이 너무 크거나 너무 작은지 메세지를 보여주는 것을 원할수 있다. 이렇게 하려면 코드의 부분을 조건부로 만들 수 있다.

스위프트는 코드의 조건 분기를 추가하는 두가지 방법을 제공한다. if, switch문이 있다. 보통 몇몇의 가능한 결과만 있는 간단한 조건을 평가하는 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."

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."

두가지 분기중 하나는 무조건 실행이 된다.

여러 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."

마지막 else절은 선택적이므로 생략이 가능하다.

Switch

switch문은 값을 고려하고, 가능한 여러 패턴 매칭을 비교한다. 그 후에 성공적으로 일치하는 첫 번째 패턴을 기반으로 적절한 코드 블록을 실행한다. switch문은 여러 잠재 상태의 응답을 위해 if문의 대안으로 제공된다.

모든 switch문은 여러 가능한 케이스로 구성되고 case라는 키워드로 시작된다. 특정 값의 비교를 더하여 스위프트는 각 경우에 대해 더 복잡한 매칭 패턴을 지정하는 여러 방법을 제공한다.

if문 내부와 같이, 각각의 case는 별도의 코드 실행 분기이다. switch문은 선택해야 하는 분기를 결정한다. 이 절차는 값의 스위칭으로 알려져있다.

모든 switch문은 철저해야한다. 그건 고려중인 모든 가능한 타입의 값은 switch케이스의 하나로서 매치가 되어야만 하는것을 의미한다. 만약 모든 가능한 값에 대해 케이스를 제공하는 것이 적절하지 않는다면, 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"

default를 작성하여 위 switch문은 완전함을 보장한다.


No Implicit Fallthrough (암시적 Fallthrough 없음)

C와 Objective-C의 스위치문과 반대로, 기본적으로 스위프트의 스위치문은 각 케이스의 마지막에서 다음 케이스로 넘어가지 않는다. 대신 전체 스위치 문은 명시적으로 break문의 요구 없이 처음 매칭되는 케이스에서 실행을 완료하자마자 실행을 종료한다. 이것은 C언어에 비해 스위치문을 더 안전하고 쉽게 사용하게 만들고, 실수로인한 하나이상의 케이스의 실행을 피하게 해준다.

NOTE

스위프트에서 break는 요구되지 않더라도 매칭을 하기위해 사용하거나, 특정케이스를 무시하거나, 실행되는 케이스가 완료되기 전에 종료를 위해 사용할 수 있다.

스위치문의 케이스는 반드시 하나의 실행 문이 필요하다. 아래의 예시는 유효하지 않은 스위치문이다.

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // 비어있기 때문에 유효하지 않다.
case "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// 컴파일 에러를 발생시킨다.

C언어의 스위치문과 다르게, 위 스위치문은 aA 둘다 매치하지 않는다.오히려 실행문이 비어있기 때문에, 컴파일 에러를 발생시킨다. 이 접근 방식은 한 케이스에서 다른 케이스로의 우발적인 실행을 방지하고 의도를 더 명확하게 하고 안전한 코드를 만듭니다.

스위치문의 하나의 케이스에 a, A를 결합하는 경우도 가능하다. 두 개가 모두 일치해야하는 단일 케이스가 된다.

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// Prints "The letter A"

가독성을 위해, 복합 케이스는 여러줄로 작성이 가능하다.

NOTE

특정 케이스의 끝에서 명시적으로 다음 케이스로 넘어가려면 fallthrough 키워드로 작성을 하면 된다.

Interval Matching (간격 일치)

각 케이스의 값은 간격을 체크하는것이 가능하다.

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."

Tuples (튜플)

튜플을 사용하여 하나의 스위치문에서 여러 값들을 테스트할 수 있다. 튜플의 각 요소들은 값과 간격에 대해 비교가 된다. 대안으로 튜플 요소에 _로 작성을 하면 이 부분은 어떠한 값도 매치가 가능하다는 의미가 된다.

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"

C언어와 달리 스위프트는 같은 값을 비교하는 여러 케이스에 대한 비교가 가능하다. 위의 경우 (0,0)을 비교하는 예시가 있다면, 4가지 케이스 전부 가능하지만 처음 케이스를 통과한 결과값이 항상 사용된다. 첫 케이스가 통과한다면 나머지 케이스는 전부 무시한다.

Value Bindings (값 바인딩)

스위치 케이스의 내부에서 사용을 하기 위한 임시 상수나 변수에 비교하는 값의 네이밍이 가능하다. 값이 케이스 내부의 임시 상수나 변수에 바인딩 되기 때문에 이 행동은 값 바인딩(value binding)으로 알려져 있다.

let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0): // anotherPoint의 x값을 쓴다는 의미
    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"

위의 경우 x축, y축 또는 나머지 어딘가에 있는 지점을 결정한다. 임시 상수가 선언된 후에, 케이스의 코드블럭 내에서 사용이 가능하다. 위 스위치문은 default가 필요하지 않다. 마지막 케이스에서 나머지 모든 값들을 가능하게 해주기 때문이다.

Where

스위치 케이스는 where절을 사용해서 추가 조건을 체크할 수 있다.

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"

위의 상수는 where절의 일부로 사용되어 동적 필터를 생성한다. where 절의 결과가 true인 경우에만 케이스를 매치한다.

Compound Cases (복합 케이스)

각 패턴에 콤마를 사이로 두고, 여러 패턴들을 작성하여 하나의 케이스에서 공유되어 결합할 수 있다. 패턴들중 하나라도 일치한다면, 그 케이스는 매치되는것으로 고려된다.

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"

위 경우, 케이스의 본문에서 항상 distance값에 접근이 가능함을 의미한다.

Control Transfer Statements (제어 변경 구문)

제어 변경 구문은 코드의 한 부분에서 다른 부분으로 제어를 전송하여 코드가 실행되는 순서를 변경한다. 스위프트는 다섯가지의 변경 구문을 가지고 있다.

  • continue
  • break
  • fallthrough
  • return
  • throw

Continue

continue문은 현재 실행문을 멈추고 다음 루프로 반복을 시작 하도록 한다. 현재 반복을 완전히 벗어나지 않고 "현재 반복을 멈추겠다"라는 의미이다.

// 모음과 공백을 지우는 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

break문은 전체의 제어 흐름문을 즉시 종료한다.

Break in a Loop Statement (반복문에서의 Break)

반복문 내부에서 사용하는 경우, 반복문 내부를 즉시 종료하고 반복문의 끝 }의 다음 코드로 전환한다. 더 이상 루프의 현재 반복에서 코드를 실행하지않고, 더 이상 반복을 시작하지 않는다.

Break in a Switch Statement (스위치문에서의 Break)

스위치문 내부에서 사용하는 경우에도 스위치 문의 끝으로 전환한다.

이 동작은 매칭을 하거나 하나 이상의 케이스를 무시할 수 있다. 스위프트의 스위치문은 완전하고 빈 케이스를 허용하지 않기 때문에, 의도를 명확하게 만들기 위해 의도적으로 케이스를 매치하거나 무시할 필요가 있다.

NOTE

스위치 케이스에 주석만 포함되면 컴파일 에러를 발생한다. 항상 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."

케이스에 매치되는 경우, 옵셔널 Int?possibleIntegerValue에 정확한 정수 값을 할당한다.

스위치문의 실행이 완료된후, 찾은 값의 옵셔널 바인딩을 사용한다. 암시적 초기값이 nil 이므로, 실제 값이 바인딩된 경우에만 옵셔널 바인딩이 성공한다.

위의 default 케이스에서는 아무런 행동이 필요 없기 때문에 break를 이용해서 무시하였다. break 케이스를 실행하자마자 스위치문은 종료되고, if let문에서 계속된다.

Fallthrough

스위프트에서 스위치문은 하나의 케이스 내부에서 다음 케이스로 넘어가지 않는다. 처음 케이스에 매치되어 완료되면 전체 스위치문은 완료된다. 반대로 C언어는 다음 케이스로 넘어가지 않게 모든 케이스에 break문이 명시적으로 필요하다. 스위프트의 스위치문이 fallthrough를 피하는 것은 C언어 보다 더 간결하고 예측 가능하므로 실수로 여러 케이스를 실행하는 것을 방지하는 것을 의미한다.

C언어와 같이 fallthrough 하려면, 케이스에 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 문을 실행하는 모습
default:
    description += " an integer."
}
print(description)
// Prints "The number 5 is a prime number, and also an integer."

NOTE

fallthrough 키워드는 케이스의 조건을 체크하지 않고 실행하게 한다. 이 키워드는 간단하게 C언어와 비슷하게 다음 케이스(or 디폴트케이스)로 넘어가게 한다.

Labeled Statements (라벨링된 구문)

스위프트에서 다른 반복문과 조건문 내부에 복잡한 제어 흐름 구조를 만들기 위해 반복문과 조건문을 끼워 넣을 수 있다. 그러나 반복문과 조건문 둘다 break문을 사용이 가능하며, 이는 조기에 실행을 종료한다. 그러므로 이러한 반복문과 조건문을 종료되기를 원하는 곳에 break문을 명시하는 것은 유용할때가 있다. 비슷하게 여러 반복문이 있다면, continue문이 영향을 미치는 루프를 명시하는 것이 유용할 수 있다.

이러한 목적을 얻기 위해, 구문 라벨(statement label)과 함께 반복문과 조건문을 작성 할 수 있다. 조건문에서 구문의 실행을 종료하는 break문을 사용하여 라벨이 지정된 구문을 종료할 수 있다. 반복문에서 구문의 실행을 종료하거나 계속하는 break, continue문을 사용하여 라벨이 지정된 구문에 사용할 수 있다.

라벨링된 구문은 같은줄에 소개 키워드 콜론(:)과 함께 표시한다. 뱀과 사다리 게임을 예시로 설명. 추가 룰로 25를 넘어가면 25에 딱 맞게 멈출 때까지 주사위를 굴려야한다.

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:
        // 25 라면 종료한다.
        break gameLoop
    case let newSquare where newSquare > finalSquare:
        // 25를 넘었다면, 현재 반복을 종료하고 다음 반복을 시작한다.
        continue gameLoop
    default:
        // this is a valid move, so find out its effect
        square += diceRoll
        square += board[square]
    }
}
print("Game over!")

NOTE

break문이 라벨없이 사용된다면, 스위치문은 종료되나, while문은 종료되지 않는다. 라벨구문을 사용하는 것은 제어문이 종료되는것을 명확하게 해준다.

continue gameloop는 루프의 다음 반복으로 점프할 때 엄격하게는 필요하지 않다. 게임에는 오직 하나의 반복이 있기 때문에 continue문의 영향은 모호하지 않다. 따라서 continue을 라벨 구문과 함께 사용하는 것은 전혀 해가 되지 않는다. 이렇게 하는 것은 break문의 라벨링과 함께 사용하는것과 일치하며, 게임의 논리를 더 명확하게 읽고 이해하는데 도움을 준다.

Early Exit (이른 종료)

if문과 같이 guard 문은 표현식의 불린값에 따라 구문을 실행한다. guard문은 guard문 다음을 실행할때 조건이 true를 요구하기 위해 사용한다. if문과 다르게 guard문은 항상 else절이 필요하다. false일시에 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."

가드문의 조건이 충족되면 해당 가드문의 끝에 다음 부터 실행된다. 조건의 일부로 옵셔널 바인딩을 사용하여 값이 할당된 변수나 상수는 나머지 코드 블록에서 사용이 가능하다.

조건이 충족되지 않는다면 else절 부분이 실행된다.

가드문을 사용하는것은, 같은 조건을 비교하는 if문에 비해 코드의 가독성이 높아진다. else 블록의 래핑없이 일반적으로 실행되는 코드를 작성할 수 있고, 요구사항을 충족하지 못하는 부분을 요구사항 다음에 바로 작성이 가능하다.

Checking API Availability (API 유효성 체크)

스위프트는 API의 유효성 체크를 내장지원하고, 주어진 배포 대상에서 사용이 불가한 API를 실수로 사용하지 못하도록 한다.

컴파일러는 사용된 API가 프로젝트의 개발 대상에서 유효한지 SDK내의 유효한 정보를 사용하여 검사한다. 스위프트는 사용 불가한 API를 만나면 컴파일 에러를 발생한다.

사용하려는 API가 런타임에 사용이 가능한지 여부에 따라 if, guard문에서 유효성 조건을 사용하여 코드 블록을 조건부로 실행한다. 컴파일러는 해당 코드 블록의 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
}

위 코드는 iOS가 10버전 이상, macOS가 10.12버전 이상, 마지막 *는 필수이며, 다른 플랫폼에서 if문의 실행은 지정한 최소 개발 대상에서 가능하게 지정한다.

iOS 11.2.6, macOS 10.13.3와 같이 더 자세하게도 작성이 가능하다.

profile
hi there 👋

0개의 댓글