본문 바로가기
Swift/Language Guide

Control Flow - #2/2

by diosmio 2021. 9. 12.

Conditional Statedments

  • 어떤 조건에 따라 다른 코드를 실행하고 싶을 때.
    • (예로, 에러가 발생한 경우에 메시지를 띄운다던지)
  • if와 switch구문이 있으며,
    • 많은 분기가 요구되지 않는 일반적인 경우 if가 사용되고
    • 분기가 많고, 조건문이 패턴 매칭인 경우 switch가 훨씬 사용도가 좋다

 

 

If문

  • 음.. 정리는 skip하자

 

 

Switch문

  • 다루고 있는 value의 모든 case가 명시되어야 하고 그렇지 않으면 default를 반드시 구현해주어야 한다 (default는 항상 마지막 case로 제시될 것)
  • (중요) 다른언어 대비 Swift에서의 switch문 특징
    1. break를 명시하지 않아도 default로 걸린다.switch integerToDescribe { case 2, 3, 5, 7, 11, 13, 17, 19: description += " a prime number, and also" fallthrough default: description += " an integer." }
      C-like 언어처럼 사용하고 싶으면 "fallthrough" 사용
      switch integerToDescribe {
      case 2, 3, 5, 7, 11, 13, 17, 19:
          description += " a prime number, and also"
          fallthrough
      default:
          description += " an integer."
      }​
    2. (Compound Cases) case 한 줄에 여러 값을 할당할 수 있다
      C-like Language
      switch anotherCharacter {
      case "a": 
      case "A":
          print("The letter A")
      		break
      default:
          print("Not the letter A")
      		break
      }​

      Swift
      switch anotherCharacter {
      case "a", "A":
          print("The letter A")
      		break
      default:
          print("Not the letter A")
      		break
      }​
    3. (Interval Matching)구간지정이 가능하다
      switch approximateCount {
      case 1..<5:
          ...
      case 5..<12:
      		...
      case 12...100:
      		...
      default:
      		...
      }​
    4. 튜플을 사용하여 여러 값을 비교할 수 있다
      • 언더바를 활용하여 don't care 표현도 가능하다
      • 구간지정도 가능
      • 여러 case에서 만족하는 (0,0)같은 경우는 최상위 case에 걸린다
      let somePoint = (1, 1)
      switch somePoint {
      case (0, 0):
          ...
      case (_, 0):
          ...
      case (0, _):
          ...
      case (-2...2, -2...2):
          ...
      default:
          ...
      }​
    5. (Value Binding) 함수처럼 인자를 전달받아 case's body에서 사용할 수 있다
      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))")
      }​

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

      • Compound case와 함께 사용할 때는 주의사항이 있다
        1. compound로 묶는 조건간 binding value는 같아야 한다
        2. 같은 코드로 쓰려면 당연히 이름이 같아야 한다
        3. compound로 묶는 조건간 binding value의 type은 모두 같아야 한다(위의 예시처럼 튜플의 first, second를 사용하려면 (Int, Int) 혹은 (String, String) 이렇게 같은 Type으로 구성된 튜플이어야 한다)
        4. 그래야 case's body에서 항상 같은 type이 사용되도록 고정할 수 있다
    6. (Where) 튜플처럼 여러 value를 사용할 때 추가 조건문을 부여할 수 있다
      • 놀랍게도.. 코드가 굉장히 보기좋다
      let yetAnotherPoint = (1, -1)
      switch yetAnotherPoint {
      case let (x, y) where x == y:
          ...
      case let (x, y) where x == -y:
          ...
      case let (x, y):
          ...
      }​

 

 

Control Transfer

  • 코드가 실행되는 순서를 바꿀때 사용된다
    • break
    • continue
    • fallthrough
    • return
    • throw
    (return은 함수파트, throw는 에러핸들링 파트에서 자세히 알아보고 나머지에 대해 알아보자)
  1. Continue
    • 현재 loop를 종료하고 다음 iteration으로 이동
  2. Break
    • entire Control flow를 종료한다
    • Swift의 switch에서는 empty case를 허용하지 않기 때문에, 아무 코드도 수행하고 싶지 않은 case도 선언은 해야 한다.
    • 이때 case's body를 비우면 컴파일 에러를 유발하므로 break를 채워주는 것으로 잘 활용된다
  3. fallthrough
    • 여러 case가 같은 코드를 수행하고 싶을 때 사용

 

 

 

Labeled Statedments

  • Nested 반복문이나 조건문을 사용하는 경우엔 break의 대상이 어느 Control Flow일지 명시가 필요하다
  • Control Flow간 구분을 위해 반복문과 조건문에 Label을 부여할 수 있다
  • 사용예시
    gameLoop: while square != finalSquare {
        diceRoll += 1
        if diceRoll == 7 { diceRoll = 1 }
        switch square + diceRoll {
        case finalSquare:
            break gameLoop
        case let newSquare where newSquare > finalSquare:
            continue gameLoop
        default:
            square += diceRoll
            square += board[square]
        }
    }​
    이 예제에선 사실 continue 구문의 Label은 없어도 되긴하다. Loop가 하나뿐이라 모호하지 않기 때문. 그래도 clean 코드를 위해 쓰자
  •  

 

 

 

Early Exit

  • guard문 역시 condition이 존재하며 if문과의 차이점은 항상 else를 정의한다는 것이며
    else문 안에는 guard문이 있는 코드 block을 exit하는 return, break 등의 구문이 반드시 있어야 한다
    (직접적인 exit은 아니지만 fatalError도 가능)
  • guard문의 condition을 true로 통과하면 brace{ } 이후로 jump하여 코드가 이어 실행된다
  • 특이사항은 guard의 condition에서 let 선언한 값을 brace{ } 이후의 나머지 코드 block에서도 사용이 가능하다
  • guard문은 if let구문처럼 Optional unwrapping 기능이 있고
    if let구문에 비해 가독성이 좋다는 장점이 있다

 

 

 

 

Checking API availability

  • Swift는 Project에서 지정한 배포 target에서의 API availability 체크를 코드레벨에서 할 수 있다
  • 컴파일러는 SDK에서 관련 정보를 사용해 작성한 코드에서 API가 사용가능한지 체크를 하고 불가 시 컴파일 에러를 report한다
  • if나 guard를 사용하여 에러 report가 아닌 case-by-case로 구현할 수도 있다
    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
    }​
    확인하고자 하는 platform을 넣으면 되고 * 은 명시되지 않은 platform은 전부 허용하겠다는 의미

 

'Swift > Language Guide' 카테고리의 다른 글

Properties - #1/1  (0) 2021.09.12
Structures and Classes - #1/1  (0) 2021.09.12
Control Flow - #1/2  (0) 2021.09.12
Functions - #1/1  (0) 2021.09.12
Type Casting - #1/1  (0) 2021.09.10

댓글