GGURUPiOS

Swift 공식 문서 정리 - (5) Control Flow 본문

Swift/공식문서 정리 ( 문법 )

Swift 공식 문서 정리 - (5) Control Flow

꾸럽 2023. 4. 19. 15:29

Control Flow

스위프트에는 다양한 제어문이 있음 while, for - in loop, if , guard , switch 등

For-In 문

for-loop 를 사용해서 배열, 숫자나 문자열의 범위만큼 반복 함

전 포스팅에서 언급했듯이 딕셔너리의 경우 튜플로 방출

만약 for 문에서 값이 필요하지 않을 경우 _를 사용해 무시 가능

색깔이 안나와
for index in 1...5 {
    print("\(index) times 5 is \(index * 5)")
}

let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
    print("\(animalName)s have \(legCount) legs")
}

While 문

while은 조건이 false가 될 때까지 명령문을 수행함. ( 반복횟수가 고정적이지 않을 때 쓰면 좋을 듯 )

while condition {
	satetments
}
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]
    }
}

Repeat - While 문

while문과 다른점은 무조건 한번은 실행 된다는 것이다. 그외는 동일

repeat { 
	statements
} while condition

조건문 (Conditional Statements)

스위프트는 코드에 조건부 분기를 추가하는 방법에 두가지 방법이 있다.

if문과 switch문임.

if문은 간단한 조건,

switch는 더 복잡한 조건에 더 적합함.

IF

해당 조건이 true일 경우 명령문 실행

var temperatureInFahrenhiet = 30 
if temperatureInFahrenheit <= 32 {
    print("It's very cold. Consider wearing a scarf.")
}

// 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.")
}

// 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.")
}

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
}
// 기본 형태

모든 가능한 값이 케이스 중 하나와 일치해야 함

그래서 아무 케이스에도 포함 안되는 Default case를 정의 할 수 있음. ( 해야함 )

암시적인 진행을 사용하지 않음

switch는 옵젝씨와 C언어와 달리 암시적 진행을 하지 않음 ( 일치하는 케이스를 만나면 자동으로 switch 구문을 빠져나감 )

하지만, 특정 지점에서 멈추도록 하려면 break 를 사용해서 나올 수 있음

인터벌 매칭이 가능 함 ( 아래는 그 예시 )

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

Switch문에서의 튜플 사용

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

값 바인딩

switch는 케이스 본문에서 사용하기 위해 임시 상수 또는 변수의 이름을 지정 가능 함.

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))")
}
// (let x, 0) 처럼 값(2)을 사용하기 위해 지정 가능

Where 절

where를 사용해서 Switch문의 조건을 확인 할 수 있음

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

// case 구문 끝에 where x == y 라는 절을 추가해서 x == y 의 조건이 일치할 때 케이스에 걸리도록 할 수 있음 
// default 문이 없어도 모든 사례가 case로 표현되었다면 default 문을 작성할 필요 없음.

복합 케이스

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

/*
case "a": //
case "b": // 
이런식이 아니라
case "a", "b" 이런 식으로 사용 가능함 
*/

제어 전송 구문 (Control Transfer Statements)

스위프트에는 5개의 제어 전송 문이 있다.

  • continue
  • break
  • fallthrough
  • return
  • throw

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"

// contains는 뒤에오는 파라미터가 포함되어있는지 확인하는 메소드. bool 반환
// g, r, e, a, t... k, e 하나씩 돌다가 charactersToRemove에 포함된 문자가 있으면
// 동작없이 반복문으로 넘어가고, 아니면 puzlleOuput에 문자를 하나 추가하는 로직 

Break

break문은 전체 명령문의 실행을 즉시 종료 함.

반복문에서의 Break문

현재 반복에서 루프 실행을 종료하고 추가 코드가 실행되지 않고, 루프의 추가 반복이 시작되지 않음

for - in { } 블록을 빠져나간다고 보면 됨

Switch 문에서의 Break 문

switch문의 실행을 종료하고 { } 뒤에 있는 코드로 제어를 전송

switch 문은 빈 사례를 허용하지 않음.

그래서 case나 default 에 추가 코드가 없이 주석만 있다면, 컴파일 오류로 보고 됨

만약 동작을 안하게 하고싶다면 주석이 아니라 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."

Fallthrough 문

스위프트는 한번 특정 case를 타면 그 switch 문은 종료 됨 ( 자동적인 break )

하지만 fallthrough를 사용하면 자동적인 break 문을 막는 효과를 가짐 → 케이스를 2개이상 탈 수 있다.

레이블 구문 ( 제어문에 이름 붙이기 ? 정도 )

복잡한 제어 흐름 구조 안에서, 명시적으로 반복 또는 조건문을 지정하는 것이 유용함

label name: while condition {
    statements
}
// 기본 구문

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!")

왜 위와같이 레이블구문을 사용해야 할까 ?

→ 만약 레이블 구문없이 break를 사용하면, break gameLoop 부분에서 while문을 종료하는 것이 아니라 switch 문이 종료 된다.

→ 즉 복잡한 흐름제어 에서는 명시적으로 어떤 구문을 어떻게 작동할 건지에 대한 논리 구조와, 가독성을 위해 레이블 구문을 사용하는 것이 좋아 보임

Guard 문

guard문은 if 문과 비슷하나, 항상 else 절이 있어야 한다. 조건이 참이 아니면 else 문 실행

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

이용가능한 API 버전 확인

스위프트에는 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
}