본문 바로가기
프로그래밍/Swift

[Swift] Control Flow (제어문)

by 별준 2021. 12. 16.

Referneces

Contents

  • For-In Loops
  • While (while, repeat-while)
  • Conditional Statements (if, switch)
  • Control Transfer Statements (continue, break, fallthrough, labeled statements)
  • Early Exit (guard)
  • Checking API Availability

Swift에서는  while 루프, if, guard, switch 그리고 break와 continue 등의 다양한 제어문을 지원합니다. 

하나씩 알아보도록 하겠습니다.

 


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!

딕셔너리를 반복하여 key-value 쌍에 액세스할 수 있습니다. 반복할 때, 딕셔너리의 각 아이템은 (key, value) 튜플로 반환되고 (key, value) 튜플의 멤버들을 명시적으로 명명된 상수로 분해하여 for-in 루프 내부에서 사용할 수 있습니다.

다음은 딕셔너리의 key를 animalName이라는 상수로, value를 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

딕셔너리는 본질적으로 순서가 정해져 있지 않기 때문에 딕셔너리를 반복할 때 검색되는 순서를 보장하지 않습니다. 

 

for-in 루프에 numeric ranges를 사용하여 반복할 수 있습니다. 다음 코드는 1에서 5까지 숫자에 5를 곱한 값을 출력합니다.

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

'...'은 closed range 연산자이며, 1...5는 1부터 5까지의 숫자 범위를 의미합니다.

위 예제 코드에서 index는 루프의 각 반복이 시작될 때 자동으로 설정되는 상수입니다. 따라서 index는 사용하기 전에 선언할 필요가 없습니다. 즉, index는 let 선언 키워드가 필요없이 암시적으로 선언됩니다.

 

만약 시퀀스에서 각 값이 필요없다면, underscore(_)를 사용하여 해당 값을 무시할 수 있습니다.

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의 거듭제곱을 계산하는데, closed range 연산자 1...power를 사용하여 1부터 10까지 반복하면서 3을 계속해서 곱합니다. 루프를 반복하면서 인덱스(카운트 값)이 필요하지 않기 때문에 '_'를 사용하여 closed range의 값을 무시하며 그 값에 대한 액세스를 제공하지 않습니다.

 

경우에 따라 half-open range 연산자(..<)를 사용할 수 있습니다. 아래 코드는 0분부터 시작해서 각 분을 마킹하는 예제로 사용되는데, 마지막 60분은 0분과 같으므로 포함시키지 않습니다.

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

만약 매 5분마다 마킹하고자 한다면, stride(from:to:by:) 함수를 사용하면 됩니다. 아래 코드는 0분부터 60분까지 5분 간격으로 for-in 루프가 반복됩니다.

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 함수는 closed range를 대체하여 사용될 수 있습니다.

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

 

위 예시에서 range, 배열, 딕셔너리, 문자열을 사용하는 for-in 루프 예제를 살펴봤습니다. 하지만 for-in 루프는 Sequence 프로토콜을 따르는 자체 클래스 및 콜렉션 타입을 포함한 어떠한 콜렉션이라도 반복할 수 있습니다. 

 


While Loops

while 루프는 특정 조건이 false가 될 때까지 반복하여 일련의 구문을 수행합니다. while 루프는 반복이 시작되기 전에 반복 횟수를 알 수 없는 경우에 자주 사용됩니다. Swift에서는 두 종류의 while 루프를 제공합니다.

  • while : 루프의 시작에서 조건을 판단
  • repeat-while : 루프의 끝에서 조건을 판단

While

while 루프는 조건을 판단함으로써 반복이 시작됩니다. 만약 조건이 true라면, 해당 조건이 false가 될 때까지 일련의 구문(while body)를 수행합니다.

while 루프는 일반적으로 아래의 형태로 사용됩니다.

while condition {
	statement
}

 

Snakes and Ladders(Chutes and Ladders) 라는 간단한 게임을 예제로 살펴보겠습니다.

이 게임의 조건은 다음과 같습니다.

게임 보드는 Int 값들의 배열로 표현됩니다. 보드의 사이즈는 finalSquare 상수에 의해 결정되고 이 값은 배열을 초기화하고 승리 조건을 체크하는데 사용됩니다. 플레이어는 보드의 바깥에서 시작하기 때문에 보드는 총 26개의 Int 배열로 초기화되고 모든 값은 0으로 초기화됩니다.

let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)

몇몇 박스는 snakes와 ladders를 위한 특정 값으로 설정합니다. ladder인 박스는 양수로 설정되고, snakes 박스는 음수로 설정됩니다.

board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

이 게임에서 우리는 간단한 주사위 굴리기를 사용할 것입니다. 랜덤 값을 생성하는 것 대신에 diceRoll 값을 0부터 시작하여 매 while 루프마다 diceRoll을 1씩 증가시키고, 만약 diceRoll이 7이라면 다시 1로 reset하도록 합니다. 따라서 diceRoll을 매 루프마다 값이 1,2,3,4,5,6,1,2,... 으로 변경됩니다.

var square = 0
var diceRoll = 0
while square < finalSquare {
    // roll the dice
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    // move by the rolled amount
    square += diceRoll
    if square < board.count {
        // if we're still on the board, move up or down for a snake or a ladder
        square += board[square]
    }
}
print("Game over!")

주사위를 굴린 후에, 플레이어는 diceRoll 값만큼 이동합니다. 25이상의 값으로 이동할 수 있는데, 그렇게 되면 게임은 끝이나게 됩니다. 이런 경우에 대처하기 위해서 코드 내에서는 내부 if문을 통해 square 값이 board 배열의 개수보다 작은지 확인합니다. 그렇지 않으면 board 배열의 범위를 넘어서는 위치를 액세스하려고 하고, 런타임 에러가 발생합니다.

while 루프 수행이 끝나면 루프를 다시 반복할 지 확인하기 위해서 루프의 조건을 체크합니다. 만약 플레이어가 25이상의 위치로 이동했다면 루프의 조건은 false로 판단되어 게임이 종료됩니다.

 

이 게임의 경우에는 게임의 길이가 명확하지 않기 때문에 while 루프가 적절합니다.

 

Repeat-While

repeat-while은 루프의 조건을 판단하기 전에 일단 루프 body를 먼저 수행합니다. 일단 한번 루프를 수행하고 나서 루프의 조건이 false가 될 때까지 계속해서 반복합니다. (다른 언어의 do-while 루프와 동일합니다.)

repeat-while 루프는 아래처럼 사용됩니다.

repeat {
	statements
} while condition

 

위에서 살펴본 Snakes and Ladders 게임을 repeat-while 루프를 사용하여 구현해보겠습니다. finalSquare, board, square, diceRoll은 위에서 본 것과 동일하게 초기화되며, 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 {
    // move up or down for a snake or ladder
    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!")

 


Conditional Statements

특정 조건에 따라 서로 다른 코드를 실행하는 것이 유용한 경우가 많은데, 이런 경우에는 코드 일부를 조건부로 만들어 주어야 합니다.

Swift에서는 조건부 분기를 추가하는 두 가지 방법을 제공하는데, 하나는 if문이고 다른 하나는 switch문 입니다. 일반적으로 if문을 사용하면 몇 가지 가능한 결과들에 대한 조건을 평가하고, switch문은 여러 가능한 순열의 더 복잡한 조건을 판단하는 상황에서 더 유용합니다.

 

If

간단한 형태로 하나의 if 조건으로 사용할 수 있습니다. if의 조건이 true인 경우에만 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."

 

다른 언어와 마찬가지로 else나 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."

조건이 완전할 필요가 없는 경우 마지막 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.")
}

 

Switch

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
}

모든 switch 구문은 가능한 여러 개의 케이스로 구성되고, 각각의 케이스는 case 키워드로 시작합니다. 특정 값과 비교하는 것 이외에도 조금 더 복잡한 패턴을 지정하는 방법들이 제공됩니다(아래에서 설명). if 구문의 body와 마찬가지로 각 case는 코드 실행에서 분리되는 분기입니다.

 

switch문은 가능한 모든 유형의 값을 고려해야하고, case 중의 하나와 일치해야 합니다. 만약 모든 가능한 값의 case가 제공되지 않는 경우에는 명시적으로 고려되지 않는 값들을 커버하기 위해서 default case를 정의할 수 있습니다. default case는 default 키워드로 지정되고, 항상 마지막에 위치해야 합니다.

다음 예제 코드는 someCharacter 상수에 영문 소문자를 고려하는 switch문을 보여줍니다.

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"

 

No Implicit Fallthrough

C 언어와는 달리 swift의 switch문은 기본적으로 각 case에서 다음 case로 넘어가지 않습니다. 이러한 장치로 인해서 switch문에 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.

위 코드는 컴파일 에러가 발생합니다. 바로 case "a": 의 body가 존재하지 않는다는 이유로 에러가 발생합니다. C언어의 경우에는 에러없이 case "a":는 case "A":로 넘어가게 되고 break를 만날 때까지 case "a": 아래쪽에 위치한 구문들을 실행하지만, swift는 하나의 case만을 실행하고 종료하게 됩니다. 따라서, 실수로 한 case에서 다른 case로 넘어가는 것을 방지해줍니다.

"a"와 "A"를 같은 case로 묶어서(compound case) 사용하려면, 두 값 사이에 콤마로 구분해주면 됩니다.

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

조금 더 자세한 내용은 아래의 Compound Cases를 참조바랍니다.. !

 

Interval Matching

아래 예제 코드처럼 값의 범위를 체크하는 것도 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."

 

Tuple

switch 문 case로 여러 개의 값을 테스트하기 위해 튜플을 사용할 수 있습니다. 튜플의 각 요소는 다른 값을 가지거나 범위에 속하는지 체크됩니다. underscore(_)를 와일드카드 패턴으로 사용하여, 모든 가능한 값을 매치시킬 수도 있습니다.

아래 코드는 (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"

 

Value Bindings

switch문의 case는 매치되는 값들을 임시 상수나 변수로 명명하여 case의 body에서 사용할 수 있습니다. 이러한 동작을 value binding이라고 하며, 값을 임시 상수나 변수로 bind합니다.

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문에는 default case가 없습니다. 마지막 case인 let (x, y)는 임의의 값에 매칭될 수 있는 두 상수 placeholder의 튜플입니다. anotherPoint는 항상 두 값의 튜플이므로 모든 경우가 case let (x, y)에 매칭되므로 default case가 필요없습니다.

 

Where

where clause를 사용하여 부가적인 조건을 체크할 수 있습니다.

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"

 

Compound Cases

여러 switch case는 각 조건 사이에 콤바로(,) 여러 개의 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"

 

Compound cases는 value binding을 포함합니다. 이 경우 binding 되는 값은 어느 조건에서나 동일한 타입의 값이어야 하고 binding되는 변수나 상수는 모든 조건(패턴)에 존재해야 합니다.

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"

아래처럼 binding 값이 모든 조건에 존재하지 않는다면 컴파일 에러가 발생합니다.


Control Transfer Statements

Control transfer statements는 코드가 실행되는 순서를 변경시켜 줍니다. Swift에서는 아래의 다섯 가지 control transfer statements를 지원합니다.

  • continue
  • break
  • fallthrough
  • return
  • throw

여기서는 continue, break, fallthrought에 대해서만 알아보고, 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문은 현재 제어문의 수행을 즉시 종료하는데, switch 또는 루프의 실행을 종료하고자 할 때 그 내부에서 사용할 수 있습니다.

 

- Break in a Loop Statement

루프 구문 내부에서 사용할 때 break는 루프의 실행 즉시 중단하고 루프가 종료되는 괄호 (}) 이후부터 계속해서 수행합니다.

 

- Break in a Switch Statement

swich문 내부에서 사용되면, break는 실행 중이던 switch문을 종료하고 switch가 종료되는 괄호 (}) 이후부터 코드를 계속해서 수행합니다. swfit에서는 빈 case를 허용하지 않기 때문에 의도를 분명하게 하기 위해서 의도적으로 break를 넣어서 일치시키거나 무시하는 case를 사용할 수 있습니다.

(default에 아무런 동작도 하지 않도록 하기 위해서 default case에 break를 넣을 수 있습니다.)

 

다음 예제 코드는 문자 값으로 switch하여 어떤 숫자를 나타내는지 확인합니다.

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

 

Fallthrough

Swift의 switch 문은 C나 다른 언어처럼 명시적으로 break를 만날 때까지 switch문을 계속해서 수행하지 않고, 일치하는 case의 body만을 수행하고 실행을 종료합니다. 만약 의도적으로 일치하는 case의 아래에 위치하는 case도 수행하고자 한다면, fallthrought를 case의 body끝에 넣어주면 됩니다. 

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

위 코드에서는 case 2, 3 ... 조건에 해당되어 해당 case의 구문을 실행하고 fallthrogh를 만나서 바로 아래 쪽에 위치하는 default case도 수행합니다. 주의해야할 점은 fallthrough를 사용하면, 바로 다음 case의 조건은 고려하지 않고 그냥 실행합니다. 그리고, 바로 아래의 case'만' 실행하므로, 해당 case 아래에 위치하는 모든 case를 실행하려면 아래쪽에 위치하는 모든 case에 명시적으로 fallthrought를 추가해주어야 합니다.

 

Labeled Statements

복잡한 제어 흐름 구조를 작성하기 위해서 다른 루프나 조건문 내부에 또다른 루프나 조건문을 중첩시킬 수 있습니다. 이 루프와 조건문은 둘 다 break문을 사용하여 실행을 종료할 수 있습니다. 그러나, 때때로 명시적으로 어떤 루프나 조건문을 종료할 지 나타내는게 유용합니다. 이를 위해서 label statement을 사용해 루프나 조건문에 마킹하여 명시적으로 종료할 루프를 지정할 수 있습니다. 그리고 루프문에서 특정 라벨 이름을 break나 continue와 함께 사용하면 해당 라벨문의 실행을 중지하거나 계속할 수 있습니다.

문법은 다음과 같습니다.

label name: while condition {
    statements
}

 

이렇게 조건이나 루프에 라벨을 명시하여, 위에서 살펴본 snakes and ladders 게임을 다시 구현해보면, 다음의 코드로 구현할 수 있습니다.

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:
        // diceRoll will move us to the final square, so the game is over
        break gameLoop
    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!")

 


Early Exit

if문과 유사하게 guard 을 사용하면 표현식의 boolean 값에 따라 구문을 실행할 수 있습니다. if문과는 다르게 guard는 항상 else하나만을 갖습니다. else는 조건이 true가 아닌 경우에만 실행됩니다.

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 브랜치 내의 코드가 실행됩니다. 

 


Checking API Availability

Swift에는 API 이용가능여부를 확인하기 위한 내장된 기능을 제공하며, 이는 주어진 배포 타겟이 사용할 수 없는 API를 실수로 사용하지 않도록 해줍니다. (Swift는 사용할 수 없는 API를 사용하려고 하면 컴파일 시 에러가 발생합니다.)

 

if나 guard문에 availability 조건을 사용하여 코드 블록을 조건부로 실행할 수 있습니다.

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 내부 구문을 수행합니다. 마지막 인수인 *은 필수입니다.

 

일반적인 형태로 플랫폼 이름과 버전의 리스트들이 availability 조건에 포함됩니다. 플랫폼 이름은 iOS, macOS, watchOS, tvOS와 같은 이름입니다. 버전은 major 버전 뿐만 아니라 iOS 11.2.6, macOS 10.13.3과 같은 minor 버전도 명시할 수 있습니다.

if #available(platform name version, ..., *) {
    statements to execute if the APIs are available
} else {
    fallback statements to execute if the APIs are unavailable
}

댓글