관리 메뉴

나만을 위한 블로그

[Swift] 조건문 (if, switch) 본문

iOS/Swift

[Swift] 조건문 (if, switch)

참깨빵위에참깨빵 2024. 1. 15. 22:28
728x90
반응형

스위프트의 조건문은 자바처럼 if, switch 2가지 있다.

 

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/controlflow/#If

 

Documentation

 

docs.swift.org

가장 간단한 형태의 if문은 단일 if 조건문이 있다. 해당 조건이 true인 경우에만 명령문을 실행한다
var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
    print("It's very cold. Consider wearing a scarf.")
}
// Prints "It's very cold. Consider wearing a scarf."
위 예에선 온도가 화씨 32도 이하인지 확인하고 맞다면 메시지가 출력된다. 아니라면 메시지가 출력되지 않고 if문의 닫는 중괄호 이후 코드가 실행된다. if문은 if 조건이 false인 상황에 대해 else 절이라는 대체 문(statement) 집합을 제공할 수 있다
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."
두 분기 중 하나가 항상 실행된다. 온도가 화씨 40도까지 높아져서 더 이상 스카프를 두르라고 할 만큼 춥지 않으므로 else 분기가 실행된다. 추가 절(clauses)을 고려하기 위해 여러 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 절은 선택사항이고 조건 집합을 완료할 필요가 없다면 제외될 수 있다...(중략)...스위프트는 값을 설정할 때 사용할 수 있는 단축 철자(shorthand spelling)를 제공한다
let weatherAdvice = if temperatureInCelsius <= 0 {
    "It's very cold. Consider wearing a scarf."
} else if temperatureInCelsius >= 30 {
    "It's really warm. Don't forget to wear sunscreen."
} else {
    "It's not that cold. Wear a T-shirt."
}


print(weatherAdvice)
// Prints "It's not that cold. Wear a T-shirt."
이 if 표현식에선 각 분기에 단일 값이 포함된다. 분기 조건이 true면 해당 분기의 값은 weatherAdvice 할당에서 전체 if식의 값으로 쓰인다. 모든 if 분기에는 해당 else if 분기 또는 else 분기가 있어서 분기 중 하나가 항상 일치하고 어떤 조건이 true인지에 무관하게 if 표현식이 항상 값을 생성하는 걸 보장한다...(중략)...타입을 명시적으로 지정해야 한다면 아래처럼 할 수 있다
let freezeWarning: String? = if temperatureInCelsius <= 0 {
    "It's below freezing. Watch for ice!"
} else {
    nil
}
if식은 에러를 발생시키거나 절대 리턴하지 않는 fatalError(_:file:line:) 같은 함수를 호출해서 예상 못한 실패에 응답할 수 있다
let weatherAdvice = if temperatureInCelsius > 100 {
    throw TemperatureError.boiling
} else {
    "It's a reasonable temperature."
}
위 예에서 if식은 예측 온도가 물의 끓는점보다 높은지 확인한다. 이 온도로 인해 if식은 문자열을 리턴하는 대신 boiling 에러를 발생시킨다. 이 if식이 오류를 던질 수 있더라도 그 전에 try를 쓰지 마라. 위 예에서 볼 수 있듯 할당 오른쪽에 if식을 쓰는 것 외에도 함수나 클로저가 리턴하는 값으로 쓸 수도 있다

 

스위프트 공식문서에서 if를 코틀린과 같이 표현식(식, expression)으로 표현하고 있다. 하지만 실제로 if-else문을 써서 변수에 값을 대입하려고 하면 컴파일 에러가 발생한다. 스위프트의 if는 문(statement)으로 취급되기 때문이다.

프로그래밍에서 식은 값을 생성하고 문은 프로그램 동작을 제어할 뿐 값을 생성하지 않는다. 그래서 코틀린처럼 스위프트에서 if-else를 통해 값을 곧바로 대입하는 건 불가능하다.

번외로 자바, C언어, 스위프트에선 if를 흔히 if문이라고 칭하지만 코틀린에선 if식이라고 한다. 일일이 구분하기 귀찮아서 if문이라고 퉁쳐서 부르기도 한다

또한 자바 / 코틀린과 다르게 if 조건을 소괄호로 감싸지 않는 걸 볼 수 있다.

 

공식문서의 if문 예시도 충분히 많고 다양하지만, 좀 더 다양하게 활용해보자. 흔히 학생의 시험 점수 범위별로 A, B, C등급을 매기는 예시를 if로 구현하는데, 스위프트의 if로 구현하면 아래와 같다.

let score = 80

if score >= 90 {
  print("A등급입니다")
} else if score >= 80 {
  print("B등급입니다")
} else if score >= 70 {
  print("C등급입니다")
} else {
  print("공부를 안 하셨군요?")
}

// B등급입니다

 

if 안에 if-else를 사용한다면 아래와 같다.

 

let age = 18
let hasPermission = true

if age >= 20 {
  if hasPermission {
    print("입장 가능")
  } else {
    print("권한이 없어 입장 불가")
  }
} else {
  print("당신은 입장하기에 너무 어립니다")
}

// 당신은 입장하기에 너무 어립니다

 

또한 let 변수에 곧바로 값을 할당하는 다른 예시는 아래와 같다. 삼항 연산자를 사용했다.

 

let speed = 80
let message = speed > 60 ? "빠르네요" : "허용범위 이내"

print(message)

// 빠르네요

 

위에서 말했듯, 변수에 곧바로 값을 할당하려고 아래와 같이 코틀린처럼 작성하면 expected initial value after '=' 컴파일 에러가 발생한다.

 

let speed = 80

let message = if speed > 60 {
  "빠르네요"
} else {
  "허용범위 이내"
}

print(message)

 

다시 말하자면 스위프트는 코틀린과 같이 if의 결과를 곧바로 변수에 대입하는 게 불가능하다. 그래서 if-else의 결과를 곧바로 변수에 할당하려면 삼항 연산자를 통해 값을 변수에 대입해야 한다. 코틀린에서 if와 else는 식으로 취급되기 때문에 값을 생성할 수 있어서 삼항 연산자를 언어 차원에서 제공하지 않는다.

코틀린에선 변수에 곧바로 if-else의 결과값을 대입할 수 있기 때문에, 이 부분은 코틀린 사용자라면 사용하다 헷갈릴 수 있는 부분이겠다.

 

switch

 

스위프트의 switch도 알아보자. 매번 if문만 쓸 수는 없는 노릇이다.

 

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/controlflow/#Switch

 

Documentation

 

docs.swift.org

switch 문은 값을 고려하고 이를 여러 일치 패턴과 비교한다. 그 다음 일치하는 첫 패턴을 기반으로 적절한 코드 블록을 실행한다. switch 문은 여러 잠재적 상태에 응답하기 위해 if문의 대안을 제공한다. 가장 간단한 형태의 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문의 본문과 마찬가지로 각 case는 코드 실행의 별도 분기다...(중략)...모든 값은 switch case 중 하나와 일치해야 한다. 가능한 모든 값에 대한 case를 제공할 수 없는 경우 명시적으로 처리되지 않은 모든 값을 포함하도록 기본 case를 정의할 수 있다. 이 기본 case는 default 키워드로 표시되며, 항상 마지막에 나타나야 한다
let someCharacter: Character = "z"
switch someCharacter {
case "a":
    print("The first letter of the Latin alphabet")
case "z":
    print("The last letter of the Latin alphabet")
default:
    print("Some other character")
}
// Prints "The last letter of the Latin alphabet"
if문과 마찬가지로 switch문에도 표현식 형식이 있다
let anotherCharacter: Character = "a"
let message = switch anotherCharacter {
case "a":
    "The first letter of the Latin alphabet"
case "z":
    "The last letter of the Latin alphabet"
default:
    "Some other character"
}


print(message)
// Prints "The first letter of the Latin alphabet"
(중략)...스위프트의 switch 문은 명시적인 break 문을 요구하지 않고 일치하는 첫 case가 완료되는 즉시 전체 switch 문의 실행이 완료된다. 이렇게 하면 C의 switch보다 더 안전하고 사용하기 쉽게 만들면서 실수로 2개 이상의 case를 실행하는 걸 막을 수 있다

 

공식문서에서 말하는 대로 스위프트의 switch에선 break가 필요없지만 break문을 써서 특정 case를 무시하거나, 어떤 case가 실행 완료되기 전에 일치한 case를 중단할 수 있다. 공식문서의 Break in a Switch Statement 항목에 이것과 관련된 내용이 설명돼 있다.

 

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/controlflow/#Break-in-a-Switch-Statement

 

Documentation

 

docs.swift.org

switch 문 안에서 break를 쓰면 switch 문이 즉시 종료되고 닫는 중괄호 뒤의 코드로 제어권이 이동한다. 이 동작은 switch 문에서 하나 이상의 case를 일치시키고 무시하는 데 쓸 수 있다. 스위프트의 switch 문은 빈 case를 허용하지 않기 때문에 의도를 명시적으로 나타내기 위해서 일부러 case를 일치시키고 무시해야 하는 경우가 있다. 무시하려는 case의 전체 본문으로 break문을 쓰면 된다. 해당 case가 switch 문과 일치하면 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."
위 예에선 1~4까지의 숫자가 라틴어, 아랍어, 중국어, 태국어 기호인지 확인한다. 일치하는 항목을 찾으면 case 중 하나가 옵셔널 Int? availableIntegerValue 변수를 적절한 정수값으로 변환한다. switch 문이 실행을 완료한 후, 위 예시에선 선택적 바인딩을 써서 값이 발견됐는지 확인한다. 이 변수는 옵셔널이기 때문에 암시적 초기값 nil을 갖는다. 따라서 선택적 바인딩은 switch 문의 첫 4가지 경우 중 하나에 의해 availableIntegerValue가 실제 값으로 설정됐을 때만 성공한다...(중략)...이 default case는 어떤 작업도 수행할 필요가 없으므로 단일 break문을 본문으로 사용해 작성됐다. default case가 일치하는 즉시 break문은 switch 문의 실행을 종료하고, if let 문부터 코드를 실행한다

 

장황하게 써 있지만 자바의 switch를 써 본 사람이라면 모두 아는 내용이다.

사용하지 않았다 하더라도 switch 문을 사용한다면 case로 여러 경우를 만든 다음, 콜론 뒤에 경우 별 호출할 코드를 작성한다. 이후 프로그램을 실행하면 일치하는 케이스가 있을 경우 해당 case의 코드가 실행된다.

또한 일치하는 case가 없을 경우 defualt가 실행되며 switch 문의 닫는 중괄호 바로 밑에 있는 코드부터 실행된다.

 

대개 switch 문을 쓰는 이유는 if-else if를 연달아 사용할 경우 코드 가독성이 안 좋아질 수 있기 때문이다. 위 switch 문의 경우 default를 포함해 5개의 case가 존재하는데, 이것은 else if 분기를 최소 4개는 써야 한다는 뜻이다. 뿐만 아니라 if 안의 조건도 || 연산자로 이어 붙여야 하기 때문에, 검사하는 값이 많을수록 코드가 어지러워지고 오타라도 난다면 디버깅하기 답답할 것이다. && 연산도 추가된다면 벌써부터 아찔하다.

여러 언어에서 긴 if-else if 체인은 코드 스멜로 분류하기도 한다. 결과적으로 너무 많은 if-else if 체인을 썼을 때의 복잡도를 낮추고, 가독성을 올리기 위해 switch 문의 사용을 고려할 수 있다. 정답은 없으니 선택은 본인 몫

반응형

'iOS > Swift' 카테고리의 다른 글

[Swift] 클래스와 구조체  (0) 2024.02.11
[Swift] 반복문 (for-in, while, repeat-while)  (0) 2024.01.17
[Swift] 변수와 상수, 자료형  (0) 2024.01.14
[Swift] Swift란?  (0) 2024.01.11
Comments