[Swift] 문법7 - Enum

LeeEunJae·2023년 3월 19일
0

iOS

목록 보기
8/14
post-custom-banner

📌 Enum

Enum 은 열거라는 뜻을 가진 Enumeration 에서 따온 용어 입니다. 한글로 번역할 때, 열거형이라는 말을 많이 사용합니다. 1월부터 12월까지 enum으로 정의해볼까요?

enum Month: Int {
    case january = 1
    case february
    case march
    case april
    case may
    case june
    case july
    case august
    case september
    case october
    case november
    case december
    
    func simpleDescription() -> String {
        switch self {
        case .january:
          return "1월"
        case .february:
          return "2월"
        case .march:
          return "3월"
        case .april:
          return "4월"
        case .may:
          return "5월"
        case .june:
          return "6월"
        case .july:
          return "7월"
        case .august:
          return "8월"
        case .september:
          return "9월"
        case .october:
          return "10월"
        case .november:
          return "11월"
        case .december:
          return "12월"
        }
      }
}


let december = Month.december
print(december.simpleDescription()) // 12월
print(december.rawValue) // 12

위 코드에서 Month는 원시값 Raw Value 로 Int 값을 갖도록 정의되었습니다. 그렇기 때문에 각 case 들은 1부터 12까지의 원시값을 가지고 있습니다. rawValue 속성이 바로 그 원시값을 가리키는데요. 반대로 원시값을 가지고 Enum을 만들 수 있습니다.

let october = Month(rawValue: 10)
print(october) // Optional(Month.october)

Month(rawValue) 의 반환값이 옵셔널인 이유는 Enum 에서 정의되지 않은 rawValue 를 가지고 생성할 경우 nil 을 반환하기 때문입니다.

let october = Month(rawValue: 15) // nil

일반적으로 enum은 rawValue 로 Int만을 가진다고 생각합니다. 적어도 다른 프로그래밍 언어에서는요.
하지만, swift 에서는 아닙니다. 아래는 String을 원시값으로 가지는 enum 입니다.

enum NetworkState: String {
    case error = "error"
    case success = "success"
    case failed = "failed"
}

enum 은 원시값을 가지지 않을 수도 있습니다. 굳이 필요하지 않을경우에는 원시값을 넣지 않으면 되겠죠.

enum NetworkState {
    case error
    case success
    case failed
    
    func networkResult() -> String {
        switch self {
        case .error:
            return "네트워크 에러"
        case .success:
            return "네트워크 통신 성공"
        case .failed:
            return "네트워크 통신 실패"
        default:
            return "알 수 없는 오류"
        }
    }
}

enum을 예측할 수 있다면, enum의 이름을 생략할 수 있습니다.
아래의 예시는 타입 어노테이션에 Enum 타입을 지정해줬기 때문에 enum의 이름을 생략할 수 있습니다.

let state: NetworkState = .failed

📌 연관값(Associated Value)을 가지는 Enum

Enum은 연관 값(Associated Values)을 가질 수 있습니다. 아래 예시는 어떤 API에 대한 에러를 정의한 것인데요. invalidParameter 케이스는 필드 이름과 메시지를 가지도록 정의되었습니다.

enum NetworkError {
    case invalidParams(String, String)
    case timeout
}

let error: NetworkError = .invalidParams("email", "이메일 형식이 올바르지 않습니다.")

이 값들을 꺼내기 위한 방법으로 if-case 또는 switch를 사용하는 방법이 있습니다

if case .invalidParams(let field, let message) = error {
    print(field)
    print(message)
}

switch error {
case .invalidParams(let field, let message):
    print(field)
    print(message)
default:
    break
}

📌 충격적 사실!

사실 옵셔널은 Enum 입니다. 실제로 이렇게 생겼어요

public enum Optional<Wrapped> {
  case none
  case some(Wrapped)
}

옵셔널이 왜 '값'과 '없는 값'을 포함하고 있다고 설명했는지, 그리고 왜 '감싸다'라는 표현을 사용했는지 이해 가시나요?
옵셔널은 Enum이기 때문에, 아래와 같은 구문도 사용할 수 있습니다.

let age: Int? = 20

switch age {
case .none: // nil인 경우
    print("나이 정보가 없습니다.")
case .some(let x) where x < 20 :
    print("청소년")
case .some(let x) where x < 65:
    print("성인")
default:
    print("어르신")
}
profile
매일 조금씩이라도 성장하자
post-custom-banner

0개의 댓글