[Swift] Enumeration

비나·2022년 8월 23일

Swift

목록 보기
4/8
post-thumbnail

📌 Enumeration

Enumeration(열거형)은 연관된 항목들을 묶어서 표현할 수 있는 타입이다.
배열이나 딕셔너리와는 다르게 정의한 값 이외에 추가 또는 수정이 불가능하다.

✅ 특징

따라서 다음과 같은 경우 잘 사용된다.

  1. 제한된 선택지를 주고 싶을 때
  2. 정해진 값 외에는 입력받고 싶지 않을 때
  3. 예상된 입력 값이 한정되어 있을 때

내가 공부하고 있는 책을 보면 위와 같이 나와있다.
사실 저렇게만 보면 잘 생각이 안될 수도 있는데, 책의 예시를 보면 이해가 잘 된다.

  • ex) 무선통식 방식 : WiFi, Bluetooth, 5G, LTE, 3G, 기타
  • ex) 학생 : 초등학생, 중학생, 고등학생, 대학생, 대학원생, 기타
  • ex) 지역 : 서울, 경기도, 강원도, 경상도, 충청도, 전라도, 제주도

책에도 나와 있는데, 열거형은 switch 구문과 만났을 때 활용도가 매우 좋아진다.
이 부분은 switch에 대하여 정리할때 같이 정리하겠다.

✅ 예제

📖 열거형 선언

열거형 선언은 아래와 같이 enum이라는 키워드로 한다.

import UIKit

enum School {
    case elementary
    case middle
    case high
    case university
    case graduate
}

귀찮으면 아래와 같이 해도 된다.

import UIKit

enum School {
    case elementary, middle, high, university, graduate
}

📖 열거형 변수

열거형 변수는 아래와 같이 생성할 수 있다.

var selectSchool: School = School.university
// 아래와 같이 university 앞에 School을 생략해도 된다.
var selectSchool: School = .university

위에 처럼 생성한 열거형 변수 selectSchool의 값으로는 School 내의 항목으로만 해줄 수 있다.
아래와 같이 School 내의 항목으로 값을 변경할 수 있다.

selectSchool: School = School.graduate
// 마찬가지로 아래와 같이 graduate 앞에 School을 생략해도 된다.
selectSchool: School = .graduate

✅ Raw Value

열거형의 각 항목 자체는 하나의 값이다.
하지만 항목마다 Raw Value(원시 값)도 가질 수 있다.

📖 Raw Value 명시

Raw Value을 가지려면 아래와 같이 열거형 이름의 오른쪽에 타입을 명시하면 된다.

import UIKit
// String 타입으로 Raw Value 가짐
enum School: String {
    case elementary = "유치원"
    case middle = "중학교"
    case high = "고등학교"
    case university = "대학교"
    case graduate = "대학원"
}

📖 Raw Value 사용

Raw Value 사용을 위해서는 rawValue 프로퍼티를 이용하면 된다.
아래와 같이 입력했을 경우의 결과를 보자.

📄 입력

import UIKit

enum School: String {
    case elementary = "유치원"
    case middle = "중학교"
    case high = "고등학교"
    case university = "대학교"
    case graduate = "대학원"
}
var selectSchool: School = .graduate
print("저는 \(selectSchool.rawValue)에 재학 중 입니다.")

💻 출력

저는 대학원에 재학 중 입니다.

✨ Raw Value을 일부만 주는 경우

Raw Value를 일부만 주는 경우 Swift가 처리하는 방법이다.

만약 Raw Value가 String 타입이라면 그냥 항목 이름을 Raw Value로 갖는다.
예를 들어 다음과 같은 코드의 경우 university의 Raw Value는 "university"가 된다.
다음 입력과 출력을 참고하자.

📄 입력

import UIKit

enum School: String {
    case elementary = "유치원"
    case middle = "중학교"
    case high = "고등학교"
    case university
    case graduate = "대학원"
}
print(School.university.rawValue)

💻 출력

university

만약 Raw Value가 Int 타입이라면 첫 항목을 기준으로 0부터 차례로 Raw Value로 갖는다.
예를 들어 다음과 같은 코드의 경우 eleven의 Raw Value는 어떻게 될까?

📄 입력

import UIKit

enum Nums: Int {
    case zero
    case one
    case two
    case ten = 10
    case eleven
}

print(Nums.zero.rawValue)
print(Nums.one.rawValue)
print(Nums.two.rawValue)
print(Nums.ten.rawValue)
print(Nums.eleven.rawValue)

💻 출력

0
1
2
10
11

위와 같이 10의 다음 숫자인 11이 eleven의 Raw Value가 되는 것을 확인할 수 있다.

✅ Associated Value

열거형 내의 항목은 자신과 연관된 Associated Value를 가질 수 있다.
가져도 되고 안가져도 된다.

📖 Associated Value 명시

Associated Value는 아래와 같이 열거형 내 각 항목 옆에 소괄호로 넣으면 된다.

import UIKit

enum Dish {
    case pizza(dough: String, topping: String)
    case salad(dressing: String)
    case chicken(withSauce: Bool)
    case friedrice
}

var myDish: Dish = Dish.salad(dressing: "balsamic")	// 발사믹 드레싱 샐러드

✨ 열거형 응용

위의 코드를 다시 보자.
보통 식당을 생각해보면 토핑이나 소스가 한정적이다.
따라서 토핑이나 소스도 열거형을 사용하면 좋다.
아래와 같이 열거형을 여러개 사용하여 나타내면 깔끔하다.

import UIKit

enum Dressing {
    case balsamic, oriental, honeyMustard
}

enum Topping {
    case cheese, pepperoni
}

enum Dish {
    case pizza(dough: String, topping: Topping)
    case salad(dressing: Dressing)
    case chicken(withSauce: Bool)
    case friedrice
}

var myDish: Dish = Dish.salad(dressing: Dressing.balsamic)

✅ 항목 순회

열거형의 모든 case들을 알아야하는 경우 CaseIterable 프로토콜을 활용하여 항목 순회를 할 수 있다.
열거형 뒤에 콜론을 찍고 CaseIterable을 채택하면 사용 가능하다.
이렇게 하면 열거형에 allCases라는 프로퍼티를 사용할 수 있는데, 이를 통해 항목 순회가 가능하다.

import UIKit

enum Nums: CaseIterable {
    case zero
    case one
    case two
    case ten
    case eleven
}

let showNums: [Nums] = Nums.allCases
// => [zero, one, two, ten, eleven]

Raw Value가 있는 경우라면 아래와 같이 Raw Value의 타입 다음에 콤마를 찍고 CaseIterable을 써주면 된다.

import UIKit

enum Nums: Int, CaseIterable {
    case zero
    case one
    case two
    case ten = 10
    case eleven
}

let showNums: [Nums] = Nums.allCases

📖 allCases를 사용할 수 없는 경우

  1. @available 속성을 넣어 플랫폼 별로 사용 조건을 추가하는 경우 CaseIterable 프로토콜을 채택하는 것만으로 allCases 프로퍼티를 사용할 수 없을 수도 있다.

  2. 열거형의 case가 연관 값을 갖는 경우 역시 allCases 프로퍼티를 사용할 수 없다.

-> 위 두가지 경우에는 직접 allCases 프로퍼티를 구현해야한다.

✅ 순환 열거형

순환 열거형은 열거형 항목이 열거형 자신의 값이고자 할 때 사용한다.
이를 명시하는 법은 indirect 키워드를 사용하는 것이다.

📖 특정 항목에 명시

특정 항목에만 순환 열거형 항목을 명시하는 경우 아래와 같이 case 키워드 앞에 indirect 키워드를 사용하면 된다.

import UIKit

enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}

📖 열거형 전체에 명시

열거형 전체에 적용하고 싶다면, enum 키워드 앞에 indirect 키워드를 사용하면 된다.

import UIKit

indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

📖 비교 가능한 열거형

Comparable 프로토콜을 준수하는 연관 값만 갖거나 연관 값이 없는 열거형은 Comparable 프로토콜 채택 시 각 case를 비교할 수 있다.
앞에 위치한 case가 더 작은 값이 된다.
아래와 같이 비교할 수 있다.

import UIKit

enum Condition: Comparable {
    case terrible
    case bad
    case soso
    case good
    case great
}

let myCondition: Condition = .great
let yourCondition: Condition = .good

if myCondition > yourCondition {
    print("My condition is better.")
}
else if myCondition < yourCondition {
    print("Your condition is better")
}
else if myCondition == yourCondition {
    print("We have same condition!")
}
else {
    print("something wrong")
}



📌 마무리

열거형은 잘 쓰면 정말 유용하게 쓸 수 있을 것 같은 개념이다.
뒤에 내용들을 정리하고 한번 더 추가로 정리할 것이 있으면 해야겠다.
개념 정리를 하니 확실히 깔끔하다.
앞으로 개념 정리를 소홀히 하지 말도록 노력해야지. 🙌✨



참고
- 야곰, 『스위프트 프로그래밍 3판』, 한빛미디어, 2021.04
- the swift programming language swift 5.7
- Swift | Apple Developer Documentation
profile
아자아자 코딩라이푸 ٩(๑❛ʚ❛๑)۶

0개의 댓글