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
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("어르신")
}