본문 바로가기
iOS, Swift/Swift

Swift enum 총정리

by Developer88 2025. 3. 31.
반응형

오늘은 swift의 enum의 기본적인 정의 방법부터,

switch와 함께 다루는 방법들까지,

다양한 예제와 함께 정리하겠습니다.

1. enum 의 정의와 기본 사용방법

enum은 관련된 값들의 그룹을 정의하게 해주는데요.

아래와 같이 정의해서 사용합니다.

 

enum Direction {
    case north
    case south
    case east
    case west
}

 

이는 좀 더 간략하게 한줄로 정의할 수도 있습니다.

 

enum Direction { case north, south, east, west }

 

이 값에 접근할 때는,

아래와 같이 해 줍니다.

 

let currentDirection = Direction.north

 

swift의 다른 속성들에 접근할 때처럼,

타입이 명확할 때는 아래와 같이 축약도 가능합니다.

 

let anotherDirection: Direction = .south

 

2. Switch로 enum 다루기

enum 값은 switch문을 이용해 처리하는 경우가 많은데요.

switch를 이용해서 enum을 다룰 때,

하나라도 누락하면 컴파일러가 경고를 해 줍니다.

 

enum Direction {
    case north
    case south
    case east
    case west
}

func getDirectionInfo(for direction: Direction) {
    switch direction {
    case .north:
        print("북쪽을 향하고 있습니다")
    case .south:
        print("남쪽을 향하고 있습니다")
    case .east:
        print("동쪽을 향하고 있습니다")
    case .west:
        print("서쪽을 향하고 있습니다")
    }
}

 

 

위 switch문을 이용해서 아래와 같은 코드를 실행할 수 있습니다.

 

getDirectionInfo(for: .east) // "동쪽을 향하고 있습니다" 출력

 

3. 연관값(associated value)이 있는 enum

enum은 아래와 같이,

단순한 이름 뿐만 아니라,

다른 유형의 값을 포함할 수 있습니다.

 

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

 

아래와 같이 값을 주고 사용할 수 있습니다.

 

let productBarcode = Barcode.upc(8, 85909, 51226, 3)
let websiteQR = Barcode.qrCode("https://www.example.com")

// 연관 값 추출하기
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
    print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)")
case .qrCode(let productURL):
    print("QR code: \(productURL)")
}

 

4.  연관값 (associated value)가 있는 경우의 비교하기

enum은 연관값(associated value)가 없다면,

기본적으로 Equatable을 자동으로 구현하므로,

특정 상태를 확인할 때, "=="을 이용하면 됩니다.

 

하지만 연관값이 있을경우에는,

if-case문을 이용해 주어야 합니다.

어떻게 하는지,

예제를 보면서 이해해 볼까요.

 

아래와 같이 간단한 Result 상태를 나타내는 열거형이 있습니다.

 

enum Result {
    case success(String)
    case failure(Int)
    case loading
    case idle
}

 

현재 상태를 아래와 같이 정의해 볼께요.

 

let currentResult = Result.success("데이터 로드 완료")

 

currentResult가 success인지 알고 싶은 경우가 있지요.

그런데 연관값이 있으므로,

Equatable이 자동으로 구현되어 있지 않아,

"=="로 비교할 수가 없습니다.

 

이럴 때 아래와 같이,

if-case문을 사용해주면 됩니다.

 

if case .success = currentResult {
    print("성공 상태입니다!")
}

if case .loading = currentResult {
    print("데이터를 로딩 중입니다...")
}

 

 

아래와 같이 특정 값을 가진 케이스만 찾을수도 있습니다.

 

if case .failure(404) = currentResult {
    print("404 에러가 발생했습니다.")
}

 

swiftUI에서 사용할 때는,

즉시 실행 함수를 이용해서 아래와 같이,

함수를 별도로 만들지 않고 전달할수도 있습니다.

 

.scaleEffect({
    if case .refreshing = viewModel.viewState {
        return 0.8
    } else {
        return 1.0
    }
}())

 

5. 원시값(raw value) 지정하기

5-1. rawValue 지정하기

swift의 enum에는 원시값을 지정하고,

rawValue로 접근할수도 있습니다.

 

특이한 점은, 아래와 같이 명시적으로 값을 지정하지 않으면,

이전 값에서 자동으로 증가시켜 준다는 것입니다.

아래에서는, 같이 지정되지 않았던 venus=2, earth=3, mars = 4가 자동으로 지정됩니다.

 

enum Planet: Int {
    case mercury = 1
    case venus
    case earth
    case mars
}

// 원시 값 가져오기
let earthNumber = Planet.earth.rawValue // 3

 

아래와 같이,

rawValue로부터 enum을 가져올 수도 있습니다.

 

if let fourthPlanet = Planet(rawValue: 4) {
    print("4번 행성은 \(fourthPlanet)입니다") // "4번 행성은 mars입니다"
}

 

guard let으로 표현한다면 아래와 같겠지요.

 

guard let fourthPlanet = Planet(rawValue: 4) else {
    print("유효한 행성이 아닙니다")
    return
}
print("4번 행성은 \(fourthPlanet)입니다") // "4번 행성은 mars입니다"

 

5-2. 문자열 rawValue

enum에서 문자열을 지정하지 않아도,

아래와 같이 타입을 지정해준다면,

자동으로 case와 동일한 문자열의 값을 할당해 줍니다.

 

enum CompassDirection: String {
    case north
    case south
    case east
    case west
}

 

아래와 같이 호출하면, 결과는 'north'가 됩니다.

 

let northName = CompassDirection.north.rawValue // "north"

 

6. 메소드와 계산 속성을 가진 enum

enum에 메소드와 속성을 넣을수도 있습니다.

enum의 메서드 내에,

switch self 블록이 사용되었는데요.

enum의 값이나 상태를 기준으로 분기 처리를 할 때,

이렇게 처리합니다.

 

enum Device {
    case iPhone, iPad, macBook, appleWatch
    
    var price: Int {
        switch self {
        case .iPhone:
            return 1000000
        case .iPad:
            return 800000
        case .macBook:
            return 2000000
        case .appleWatch:
            return 500000
        }
    }
    
    func info() -> String {
        return "\(self) 가격은 \(price)원입니다"
    }
}

 

 

위의 enum을 이용해서,

macBook의 가격과 정보를 보려면 아래와 같이,

price속성과 info()메소드에 접근하면 됩니다.

 

let myDevice = Device.macBook
print(myDevice.price) // 2000000
print(myDevice.info()) // "macBook 가격은 2000000원입니다"

 

좀 더 복잡한 케이스를 볼까요?

 

커피는 메뉴 종류와, 샷의 수, 우유양, 그리고 토핑의 유무에 따라서,

가격이 다르게 책정되어 하는데요.

아래에서는 enum과 switch self블록을 이용해,

이것들을 나타내었습니다.

 

enum Coffee {
    case americano(shots: Int)
    case latte(shots: Int, milkAmount: Double)
    case cappuccino(shots: Int, milkAmount: Double, cinnamonTopping: Bool)
    
    func getPrice() -> Double {
        switch self {
        case .americano(let shots):
            return Double(shots) * 1000 + 1500
        case .latte(let shots, let milkAmount):
            return Double(shots) * 1000 + milkAmount * 500 + 2000
        case .cappuccino(let shots, let milkAmount, let cinnamonTopping):
            let basePrice = Double(shots) * 1000 + milkAmount * 500 + 2500
            return cinnamonTopping ? basePrice + 500 : basePrice
        }
    }
    
    func getDescription() -> String {
        switch self {
        case .americano(let shots):
            return "아메리카노 (에스프레소 \(shots)샷)"
        case .latte(let shots, _):
            return "라떼 (에스프레소 \(shots)샷)"
        case .cappuccino(let shots, _, let cinnamonTopping):
            let toppingDesc = cinnamonTopping ? ", 시나몬 토핑 추가" : ""
            return "카푸치노 (에스프레소 \(shots)샷\(toppingDesc))"
        }
    }
}

 

 

위 enum을 통해서,

카푸치노에 샷2, 밀크는 200, 시나몬토핑을 얹히면,

그에 대한 설명과 가격을 메소드들을 통해서,

아래와 같이 얻을 수 있습니다.

 

let myCoffee = Coffee.cappuccino(shots: 2, milkAmount: 200, cinnamonTopping: true)
print(myCoffee.getDescription())  // 출력: 카푸치노 (에스프레소 2샷, 시나몬 토핑 추가)
print(myCoffee.getPrice())        // 출력: 5500.0

 

마지막으로,

ApiEndpoint의 enum을 정의한 예제코드를 보겠습니다.

 

아래 코드에서 사용된, url과 parameters는 계산속성입니다.

 

url은 case에 따라서,

인자로 들어온 값과 함께 url을 생성해 리턴해주고요.

 

parameter는,

case에 따라,

키는 문자열,

값은 어떤 타입이든 가능한 딕셔너리형태로 리턴해주고 있습니다.

 

참고로 fetchUser의 경우,

빈 딕셔너리([:])를 반환하고 있는데요.

이 API 호출에는 URL 외에 추가 매개변수가 필요 없다는 것을 뜻합니다.

 

enum APIEndpoint {
    case login(username: String, password: String)
    case fetchUser(id: Int)
    case updateProfile(id: Int, name: String, bio: String)
    
    var url: URL {
        let baseURL = "https://api.example.com"
        
        switch self {
        case .login:
            return URL(string: baseURL + "/auth/login")!
        case .fetchUser(let id):
            return URL(string: baseURL + "/users/\(id)")!
        case .updateProfile(let id, _, _):
            return URL(string: baseURL + "/users/\(id)/profile")!
        }
    }
    
    var parameters: [String: Any] {
        switch self {
        case .login(let username, let password):
            return ["username": username, "password": password]
        case .fetchUser:
            return [:]
        case .updateProfile(_, let name, let bio):
            return ["name": name, "bio": bio]
        }
    }
}

 

위에서 정의한 ApiEndpoint는 아래와 같이 사용할 수 있습니다.

userParams는 비어있는 딕셔너리를 리턴하는데요.

실제 api호출을 할 때,

isEmpty가 true인지를 보고, 

비어있는 parameter는 추가하지 않도록 하면 되겠지요.

 

// 로그인 API 호출
let loginEndpoint = APIEndpoint.login(username: "user123", password: "securePassword")
let loginParams = loginEndpoint.parameters
// 결과: ["username": "user123", "password": "securePassword"]

// 사용자 정보 가져오기
let userEndpoint = APIEndpoint.fetchUser(id: 42)
let userParams = userEndpoint.parameters
// 결과: [:]

// 프로필 업데이트
let updateEndpoint = APIEndpoint.updateProfile(id: 42, name: "홍길동", bio: "iOS 개발자")
let updateParams = updateEndpoint.parameters
// 결과: ["name": "홍길동", "bio": "iOS 개발자"]

 

 

이상으로 swift의 enum을 다양한 예제와 함께 정리해 보았습니다.

728x90

댓글