[Swift] 열거형(Enumeration)

민니·2022년 7월 15일
0

Swift 문법

목록 보기
14/17

열거형 ❓

하나의 주제로 연관된 데이터들이 멤버로 구성되어 있는 자료형 객체

  • 열거형에서 데이터들은 열거형 객체를 정의하는 시점에 함께 정의
  • 데이터를 함부로 삭제하거나 변경할 수 없음
  • 변경하거나 삭제하려면 객체 정의 구문을 직접 수정해야 함

UIDatePicker을 사용할 때(https://velog.io/@vvkkiie/iOS-UIDatePicker-DateFormatter) date picker의 스타일을 .wheels로 지정해 준 적이 있었다.

self.datePicker.preferredDatePickerStyle = .wheels

이때 UIDatePickerStyle을 Apple 공식 문서에 서치해 보면,


이렇게 열거형으로 정의되어 있음을 알 수 있음 😁



이럴 땐 열거형 객체를 활용해라!

  • 원치 않는 값이 잘못 입력되는 것을 막고 싶을 때
  • 입력받을 값을 미리 특정할 수 있을 때
  • 제한된 값 중에서만 선택할 수 있도록 강제하고 싶을 때

📚 Example

방향 - 동, 서, 남, 북
직급 - 사원, 대리, 과장, 차장, 부장, 이사, 사장
지역 - 서울, 부산, 강원, 충남, 충북, 경남, 경북, 전남, 전북, 제주

➡️ 무한히 늘어나지 않고, 미리 특정할 수 있는 값
➡️ 공통된 주제로 연관되는 값



열거형의 정의

📚 열거형 기본 정의 형식

enum 열거형 이름 {
	//열거형의 멤버 정의
    case 멤버값 1
    case 멤버값 2
    case 멤버값 3
    case ...
}

📚 한꺼번에 멤버 선언도 가능함

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

📚 사용하기

let N = Direction.north
let S = Direction.south
let E = Direction.east
let W = Direction.west

📚 열거형 타입 명을 생략하는 경우

directionToHead 변수를 선언해 보자.

var directionToHead = Direction.west
directionToHead = .east

✏️ 이 변수는 Direction 타입임을 확인할 수 있음

✏️ 이 변수를 Direction 타입으로 정의하고 나면 이 변수에 대입될 수 있는 값은 Direction 타입에 정의된 다른 멤버값들뿐 ❗️
✏️ 열거형 타입에 속한다는 값이라는 것을 알려주기 위해 점(dot) 붙여주기
✏️ directionToHead = .east: directionToHead 변수가 Direction 타입으로 정의된 것을 컴파일러가 알고 있기 때문에, 열거형 타입명을 생략할 수 있다


var directionSample = .east

✏️ 변수나 상수를 선언할 때, 열거형 타입을 생략하고 멤버값만 적어버리면 멤버가 어떤 열거형에 소속된 값인지를 알 수 없음


var directionSample: Direction = .west

Q. 그렇다면 이런 경우는?
A. 물론 가능하다! 타입 어노테이션을 통해 directionSample의 타입이 Direction임을 알 수 있기 때문


정리

  • 열거형 타입으로 정의된 변수에는 열거형 타입명을 생략하고 멤버값만 대입해도 오류 발생 ❌
  • 변수나 상수의 타입 어노테이션을 명시한 후, 처음부터 타입명을 생략하고 멤버값만 대입해도 오류 발생 ❌
  • 타입 어노테이션 없이 변수나 상수를 초기화할 때 타입명은 생략 불가


Switch 구문과 열거형

열거형 타입으로 정의된 변수는 switch 구문에서 열거형의 멤버와 비교하는 분기 구문을 사용할 수 있음

📚 정의 형식

switch 비교 대상 {
	case 열거형.멤버1:
    	//실행할 구문
    case 열거형.멤버2:
    	//실행할 구문
    ...
}

📚 Example

var directionToHead = Direction.west

switch directionToHead {
    case Direction.north:
        print("북쪽입니다")
    case Direction.south:
        print("남쪽입니다")
    case Direction.east:
        print("동쪽입니다")
    case Direction.west:
        print("서쪽입니다")
}
//결과: 서쪽입니다

⬇️ 얘도 가능!

switch directionToHead {
    case .north:
        print("북쪽입니다")
    case .south:
        print("남쪽입니다")
    case .east:
        print("동쪽입니다")
    case .west:
        print("서쪽입니다")
}
//결과: 서쪽입니다

✏️ switch 구문 다음의 변수를 통해 비교대상의 타입이 열거형임을 알 수 있으므로, 열거형 타입명이 생략 가능


  • 열거형에 정의된 멤버를 switch 구문의 case 블록 비교에 모두 사용하면 default 구문은 생략할 수 있다.

멤버와 값의 분리

데이터를 그대로 멤버로 사용하면 이해하기 힘든 경우, 멤버와 값을 분리하여 사용

예시를 봅시닷~~ 쉽게 이해 가넝 😆

📚 Example

대표적인 예로 HTTP 응답 코드가 있음.

HTTP 응답 코드의 의미
200 정상적인 응답
304 캐싱된 데이터 전송
404 존재하지 않는 URL 또는 페이지 없음
500 서버 에러

전문가가 아니라면, 이런 숫자 코드만 보고 어떤 내용인지 파악하기 힘들지 않을까? 🤔
200,300, 304, 404, 500 등을 멤버로 정의해서 열거형을 정의한다 하더라도, 필요한 내용에 맞는 코드가 뭔지 매번 찾아봐야 함.........


이를 해결하기 위해, 멤버와 값을 분리하여
멤버는 이해하기 쉬운 문자열 위주로 정의,
실질적인 값은 HTTP 응답코드(Int 타입)로 지정하고,

열거형의 멤버에 실질적인 값을 할당한다면... ❓

enum HTTPCode: Int {
    case OK = 200
    case NOT_MODIFY = 304
    case INCORRECT_PAGE = 404
    case SERVER_ERROR = 500
}

✏️ 멤버에 별도의 값을 대입할 때는, 멤버에 대입할 값의 자료형을 열거형 타입의 선언 뒤에 타입 어노테이션으로 표현해 줘야 함(enum HTTPCode: INT)
✏️ 열거형 HTTPCode는 멤버가 정수 형태의 값을 할당받는다는 것을 의미

📚 사용

  • rawValue 속성 활용
HTTPCode.OK.rawValue //200
HTTPCode.NOT_MODIFY.rawValue //304
HTTPCode.INCORRECT_PAGE.rawValue //404
HTTPCode.SERVER_ERROR.rawValue //500  

자동 할당 기능

Rank 열거형을 선언하고, 첫 번째 멤버에만 1의 값을 할당해 봅시닷

enum Rank: Int {
    case one = 1
    case two, three, four, five
}

멤버 two~five 모두 아무 값을 대입하지 않았음에도
1에서부터 차례대로 +1 값을 증가시키며 값을 가짐

Rank.one.rawValue //1
Rank.two.rawValue //2
Rank.three.rawValue //3
Rank.four.rawValue //4
Rank.five.rawValue //5

첫 번째 멤버만 10으로 지정하면,
10에서부터 차례대로 +1 값을 증가시키며 값을 가짐

Rank.one.rawValue //10
Rank.two.rawValue //11
Rank.three.rawValue //12
Rank.four.rawValue //13
Rank.five.rawValue //14

연관 값

열거형 객체를 사용하는 시점에서 멤버에 보조 값을 설정할 수 있는 방법

ImageFormat 열거형을 선언해 봅시닷

enum ImageFormat {
    case JPEG
    case PNG(Bool)
    case GIF(Int, Bool)
}

✏️ 이미지 포맷을 정의하는 열거형임
✏️ PNG는 배경값이 투명한 PNG와 투명하지 않은 PNG 포맷으로 나뉨
✏️ GIF도 사용된 컬러 수와, 애니메이션 여부에 따라 나눌 수 있음
✏️ 이러한 특성을 모두 반영하여 멤버를 정의하면 멤버의 수가 매~~우 늘어난닷
✏️ 이때 연관 값을 사용하면 적은 멤버 수로 다양한 포맷 처리 가능

var newImage = ImageFormat.JPEG
newImage = .PNG(true)
newImage = .GIF(256, true)

열거형의 프로퍼티와 메서드

  • 내부에 연산 프로퍼티와 메서드를 정의 가능
  • 열거형의 멤버를 인스턴스처럼 활용할 수 있어, 인스턴스 프로퍼티/메서드 & 타입 프로퍼티/메서드 모두 사용 가능

📚 Example

enum HTTPCode: Int {
    case OK = 200
    case NOT_MODIFY = 304
    case INCORRECT_PAGE = 404
    case SERVER_ERROR = 500
    
    //연산 프로퍼티
    var value: String {
        return "HTTPCode number is \(self.rawValue)"
    }
    
    //인스턴스 메서드
    func getDescription() -> String {
        switch self {
            case .OK:
                return "응답이 성공했습니다. HTTP 코드는 \(self.rawValue)입니다"
            case .NOT_MODIFY:
                return "응답이 성공했습니다. HTTP 코드는 \(self.rawValue)입니다"
            case .INCORRECT_PAGE:
                return "응답이 성공했습니다. HTTP 코드는 \(self.rawValue)입니다"
            case .SERVER_ERROR:
                return "응답이 성공했습니다. HTTP 코드는 \(self.rawValue)입니다"
        }
    }
    
    //타입 메서드
    static func getName() -> String {
        return "This Enumeration is HTTPCode"
    }
}

var response = HTTPCode.NOT_MODIFY
response = .OK

response.value //HTTPCode number is 200"
response.getDescription() //응답이 성공했습니다. HTTP 코드는 200입니다

HTTPCode.getName() //This Enumeration is HTTPCode

✏️ getDescription() 메서드는 인스턴스 메서드 성격이므로 response에서 호출
✏️ getName() 메서드는 타입 메서드이므로 열거형 타입 자체에서 호출





🔗
꼼꼼한 재은씨의 Swift: 문법편

0개의 댓글