궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
SWIFT/Grammar

Swift : 기초문법 [스위치 - Switch(break/fallthrough)]

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

 

Switch

switch 구문도 소괄호(())를 생략할 수 있습니다. 단, break 키워드 사용은 선택 사항입니다. 즉, case 내부의 코드를 모두 실행하면 break 없이도 switch 구문이 종료된다는 의미입니다. 이것은 예상치 못한 실수를 줄이는 데도 큰 도움이 됩니다. 따라서 break를 사용하지 않고 case를 연속 실행하던 트릭을 더 이상 하용하지 못합니다. 그렇기 때문에 swift에서 switch 구문의 case를 연속 실행하려면 fallthrough키워드를 사용해야 합니다.

Switch 구문의 기본 형태

switch 비교값 {
case 패턴:
  /*실행구문*/

default:      //else if 같은 개념
  /*실행구문*/
}
  • switch문을 잘 사용하면 if 문 보다 읽기가 훨씬 쉽습니다.
  • 매우 한정적인 값 (enum, case 등)이 비교 값이 아닌 한 default 구문은 반드시 작성해야 합니다.
  • casebreak를 추가하지 않아도 자동으로 case 마다 break 됩니다.
  • fallthrough 키워드를 사용하여 break 되는 것을 무시할 수 있습니다.
  • fallthrough는 원하는 만큼 여러 번 사용 할 수 있습니다.
  • 원하는 만큼 많은 case를 작성 할 수 있습니다.

'if'와 'else if'를 사용하는 여러 조건이 있는 경우Switch case라고 하는 다른 구조를 사용하는 것이 더 명확해지는 경우가 많습니다. 이 접근 방식을 사용하여 조건을 한 번 작성한 다음 가능한 모든 결과와 각 결과에 대해 어떤 결과가 발생해야 하는지 나열합니다.

 

C 언어에서는 정수 타입만 들어갈 수 있었지만, swift에서는 switch 구문의 조건에 다양한 값이 들어갈 수 있습니다. 다만 각 case에 들어갈 비교 값은 입력 값과 데이터 타입이 같아야 합니다. 또, 비교될 값이 명확히 한정적인 값이 아닐 때는 default를 꼭 작성해줘야 합니다. 또한 각 case에는 범위 연산자를 사용할 수도, where 절을 사용하여 조건을 확장할 수도 있습니다.

 

말이 어렵나요? 예문을 보면서 확인해 보도록 하겠습니다.

switch 입력 값 {
    case 비교 값1
    //실행 구문
    case 비교 값2
    //실행 구문
    
    // 이 case를 마치고 switch 구문을 탈출하지 않음. 아래 case로 계속 진행
    fallthrough
    
    case 비교 값3, 비교 값4, 비교 값5 // 한 번에 여러 값과 비교 가능
    break // 탈출(종료)
    
    default : // 한정된 범위가 명확하지 않다면 default사용 필수
    
    //실행 구문
}

이제 switch 구문과 if else 문을 비교하면서 살펴보도록 하겠습니다.

let chr = "a"

if chr == "a" {
    print("캐릭터는 a 입니다.")
}
else if chr == "b" {
    print("캐릭터는 b 입니다.")
}
//캐릭터는 a 입니다.

if문을 Switch문으로 바꾸면 아래 코드와 같습니다.

let chr = "a"   //"b" 로 바꾸면 결과값은 "이것은 b 입니다."로 바뀜

switch chr {
case "a" :
    print("이것은 a 입니다.")
case "b" :
    print("이것은 b 입니다.")
default:
    print("아무것도 선택되지 않았습니다.")
}
//이것은 a 입니다.

아래 if 문을 Switch 문으로 바꿔보세요.

func loveCalculator() {
    let loveScore = Int.random(in: 0...100)
    
    if loveScore > 80 {
        print("당신은 서로 많이 사랑합니다.")
    } if loveScore > 40 && loveScore <= 80  {
        print("당신은 썸을 타고 있습니다.")
    } else {
        print("당신은 평생 혼자입니다..")
    }
}
loveCalculator()

Switch

func loveCalculator() {
    let loveScore = Int.random(in: 0...100)
    
    switch loveScore {
    case 81..100:
      print("당신은 서로 많이 사랑합니다.")
    case 41..<81:
      print("당신은 썸을 타고 있습니다.")
    case ...40:
      print("당신은 평생 혼자입니다..")
    default:
      print("다시 실행해주세요")
let weather = "sunny"

switch weather {
case "rain":
    print("Bring an umbrella")
case "snow":
    print("Wrap up warm")
case "sunny":
    print("Wear sunscreen")
default:
    print("Enjoy your day!")
}

위에 코드처럼 작성하게 되면 프린트 값 "wear sunscreen"을 반환받게 됩니다. 각 case 에는 break가 자동 설정 되어서 true값을 얻게 되면 자동으로 구문에서 빠져나오게 됩니다.

 

하지만 break값을 무시하고 다음 코드로 계속 실행하려면 fallthrough를 구문에 추가해주면 됩니다,

switch weather {
case "rain":
    print("Bring an umbrella")
case "snow":
    print("Wrap up warm")
case "sunny":
    print("Wear sunscreen")
    fallthrough
default:
    print("Enjoy your day!")
}
//Wear sunscreen
//Enjoy your day!
let liveAlbums = 2

switch liveAlbums {
case 0:
    print("첫번째")

case 1:
    print("두번째")

case 2:
    print("세번째")

default:
    print("default")
}
//세번째
let liveAlbums = 5

switch liveAlbums {
case 0...1:
    print("첫번째")

case 2...3:
    print("두번째")

case 4...5:
    print("세번째")

default:
    print("default")
}
//세번째
let integerValue: Int = 5

switch integerValue {
case 0:
    print("Value == zero")
case 1...100:
    print("Value == 1~10")
    fallthrough
    
case Int.min..<0, 101..<Int.max:
    print("Value < 0 or Value > 100")
    break
    
default:
    print("10 < Value <= 100")
}

//출력
//Value == 1~10
//Value < 0 or Value > 100

integerValue의 값이 5이기때문에 switchcase 1...100을 충족시켰고, fallthrough키워드를 사용하여 다음 case도 실행되도록 했기 때문에 case블록 3이 실행되서 출력된 것을 확인할 수 있습니다.

다양한 값 타입 사용

switch 구문의 입력 값으로 숫자 표현이 아닌 문자, 문자열, 열거형, 튜플, 범위, 패턴이 적용된 타입 등 다양한 타입의 값도 사용 가능합니다.

let stringValue: String = "서근 개발노트"

switch stringValue {
case "서근":
    print("안녕하세요 서근입니다.")
case "미진":
    print("안녕하세요 미진입니다.")
case "포뇨", "소피아", "캘시퍼":
    print("안녕하세요. \(stringValue)")
default:
    print("안녕하세요 \(stringValue)에 찾아와주셔서 감사드립니다")
}

// 안녕하세요 서근 개발노트에 찾아와주셔서 감사드립니다

case 블럭의 "포뇨", "소피아", "캘시퍼": 처럼 여러 개의 항목을 항 번에 case로 지정해주는 것도 가능합니다. 그렇지만 여러 항목을 나타내기 위해 case를 연달아 쓰는 것은 불가능합니다. case XXX: 다음에는 꼭 실행 가능한 코드가 위치해야 합니다.

잘못된 case 사용

let stringValue: String = "서근 개발노트"

switch stringValue {
case "서근":
    print("안녕하세요 서근입니다.")
case "하울":
    //실행될 코드가 없기 때문에 오류 발생
default:
    print("안녕하세요 \(stringValue)에 찾아와주셔서 감사드립니다")
}

// 안녕하세요 서근 개발노트에 찾아와주셔서 감사드립니다

위처럼 "하울" case에 실행 코드가 없기 때문에 컴파일 오류가 발생했씁니다. 만약 C 언어의 switch처럼 break를 사용하지 않은 경우 그 다음 case 블록을 실행하도록 했던 트릭을 swift에서 구현하고자 한다면 fallthrough를 사용해야 합니다.

let stringValue: String = "서근 개발노트"

switch stringValue {
case "서근":
    fallthrough
case "미진":
    fallthrough
case "하울":
    fallthrough
case "포뇨", "소피아", "캘시퍼":
    print("안녕하세요. \(stringValue)")
default:
    print("안녕하세요 \(stringValue)에 찾아와주셔서 감사드립니다")
}

// 안녕하세요 서근 개발노트에 찾아와주셔서 감사드립니다

튜플사용

typealias NameAge = (name: String, age: Int)

let tupleValue: NameAge = ("서근", 26)

switch tupleValue {
case ("미진", 20):
    fallthrough
case ("서근", 26):
    print("정확히 맞췄습니다! 저는 \(tupleValue.name) 입니다.")
default:
    print("누굴 찾고 계신가요? 아마 당신의 이름은 \(tupleValue.name) 입니다.")
}

// 정확히 맞췄습니다! 저는 서근 입니다.

위 코드는 튜플이 굳이 필요하지 않습니다. 단지 예제 일 뿐이죠. 하지만 튜플은 이외에도 와일드카드 식별자와 함께 사용하면 좀 더 유용합니다. 와일드카드 식별자(_) 는 switch 구문 외에도 여러 곳에 사용됩니다.

typealias NameAge = (name: String, age: Int)

let tupleValue: NameAge = ("서근", 26)

switch tupleValue {
case ("미진", _):
    fallthrough
case ("서근", _):
    print("이름만 맞췄습니다! 제 나이는 \(tupleValue.age)살 입니다.")
    fallthrough
case (_, 26):
    print("나이만 맞췄습니다! 제 이름은 \(tupleValue.name) 입니다.")
default:
    print("누굴 찾고 계신가요? 아마 당신의 이름은 \(tupleValue.name) 입니다.")
}

/*
이름만 맞췄습니다! 제 나이는 26살 입니다.
나이만 맞췄습니다! 제 이름은 서근 입니다.
*/

where 키워드 사용

where키워드를 사용하여 case의 조건을 확장할 수 있습니다.  where에 관한 문법은 다음에 따로 게시물로 다루겠습니다.

let IceCream: String = "비비빅"
let price: Int = 400
let isDelicious: Bool = false

switch IceCream {
case "비비빅" where isDelicious == true:
    print("아주 맛있다!")
case "비비빅" where price < 1000 && isDelicious == false:
    print("\(IceCream)...? 제가 별로 싫어하는것을 사오셨네요..")
case "비비빅" where price > 200:
    print("와 엄청 싸다!")
case "메로나":
    print("메로나")
default:
    print("맛이 없네요...")
}

// 비비빅...? 제가 별로 싫어하는것을 사오셨네요..

열거형 사용

열거형과 같이 한정된 범위의 값을 입력 값으로 받게 될 때 값에 대응하는 각 case를 구현한다면 default를 구현하지 않아도 됩니다. 만약 값에 대응하는 각 case를 구현하지 않는다면 default는 필수입니다.

enum School {
    case 유치원, 초등학교, 중학교, 고등학교, 대학교
}

let 나의학력: School = .대학교

switch 나의학력 {
case .유치원:
    print("저의 최종학력은 \(School.유치원) 입니다.")
case .초등학교:
    print("저의 최종학력은 \(School.초등학교) 입니다.")
case .중학교:
    print("저의 최종학력은 \(School.중학교) 입니다.")
case .고등학교:
    print("저의 최종학력은 \(School.고등학교) 입니다.")
case .대학교:
    print("저의 최종학력은 \(School.대학교) 입니다.")
}

// 저의 최종학력은 대학교 입니다.

Unknown

만약 열거형에 case가 추가될 가능성이 있다면 switch 구문에서는 어떻게 해야 할까요?

위 코드처럼 열거형에 정의한 모든 case를 처리해주면 정상적으로 컴파일되겠지만, 나중에 열거형에 case를 추가한다면 기존의 switch 구문은 컴파일 오류가 발생하게 될 것입니다. switch 구문은 모든 case에 대해 대비하지 못하기 때문이죠. 이럴 때는 unknown이라는 속성을 사용하여 대처할 수 있습니다.

enum Menu {
    case Pizza
    case Chicken
}

let lunchMenu: Menu = .Pizza

switch lunchMenu {
case .Chicken:
  print("양념치킨")
case .Pizza:
print("도미노피자!")
case _:  // default와 같은 표현
print("치킨소스 추가해주세요")

}

//도미노피자!

Menu라는 열거형에 나중에 case를 추가할 거 같아서 해당 열거형의 값을 처리하는 switch 구문의 마지막 case로 와일드카드 case(_)를 미리 추가했습니다. 그러면 나중에 Menu 열거형에 case를 추가해도 switch 구문에서 컴파일 오류가 발생하지 않게 됩니다.  

 

그런데 만약 나의 동료 또는 제가 나중에 Menu 열거형에 새로운 case를 추가했다고 해볼게요. 그리고 구현해둔 switch 구문의 내부 코드를 수정하지 않았다고 가정해보겠습니다. 그러면 오히려 case _ 의 상황이 발생할 가능성이 있기 때문에 문법적으로 오류가 없지만 논리적으로 오류가 발생할 수 있는 충분한 여지가 생기게 됩니다. 이런 문제를 방지하기 위해 unknown 속성을 사용할 수 있습니다.

enum Menu {
    case Pizza
    case Chicken
    case Hamburger
}

let lunchMenu: Menu = .Pizza

switch lunchMenu {
case .Chicken:
  print("양념치킨")
case .Pizza:
print("도미노피자!")
@unknown case _:  // default와 같은 표현
print("치킨소스 추가해주세요")
    
}

이렇게 Menu 열거형에 Hamburger case를 추가했고, case _: 앞에 unknown속성을 추가했습니다. unknown 속성을 부여해주면 case _ 에서 아래와 같이 경고가 발생합니다.

모든 switch 구문이 모든 case에 대응하지 않는다는 컴파일러 경고를 주고 있네요. 이처럼 논리적인 오류에 대해 도움받을 수 있는 unknown 속성을 부여할 수 있는 case는 위 코드처럼 case _ 혹은 default case 뿐입니다. 또, unknown 속성을 부여한 caseswitch 구문의 가장 마지막에 case로 작성해야 합니다.

언제 if를 대신에서 Switch문을 사용해야 하나요??

switch구문은 변수를 입력받아 미리 정해놓은 여러 값들과의 일치 여부를 판단하여 switch문 내의 control flow를 결정합니다.

 

if else구문은 불리언의 결과 값을 내놓는 조건문에 따라 true, false에 해당하는 각각 두 개의 흐름으로 갈라집니다.

 

if else문을 중첩되게 배치하면, 두 개의 흐름뿐만 아니라 세 개, 네 개 등등.. 그 이상의 control flow을 가질 수 있게 됩니다.(if / else if / else와 같은 방식)

 

if else구문을 쓸 수 있는 모든 상황에 switch문을 쓸 수 있는 건 아니지만, 반대로 모든 switch 구문은 if else문으로 대체될 수 있습니다.

 

즉, 하나의 변수를 입력받아 그 변수의 값에 따라 다른 흐름으로 이동할 수 있는 코드를 짜야할 때에 switch문과 if else구문이 둘 다 사용될 수 있음을 알 수 있습니다.

 

결론부터 말하자면, switch문을 사용하는 것이 좋습니다.

 

Switch TEST :  문제를 풀려면 이곳을 클릭해주세요.

지금까지 배운 것을 요약하자면...

  1. Swift에는 산술과 비교를 위한 연산자가 있습니다.
  2. 변수를 수정하는 산술 연산자의 복합 변형이 있습니다 : +=-=
  3. ifelse 및 else if조건의 결과에 따라 코드를 실행합니다.
  4. Swift에는 truefalse에 따라 조건을 실행하는 삼항 연산자가 있습니다.
  5. 동일한 값을 사용하는 여러 조건이 있는 경우 if 대신 switch를 사용하는 것이 더 명확합니다.
  6. 범위인 ..<와 ...마지막 숫자가 제외인지 또는 포함해야 하는지 여부에 따라 달라집니다.

 

읽어주셔서 감사합니다🤟

 

 

 


잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.