Programming/Swift

[Swift] Enumeration (열거형) 살펴보기

devssun 2019. 7. 10. 22:20
728x90
반응형

Swift - Enumeration (열거형)

An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.

Swift의 열거형은 C나 C++ 처럼 0을 기본 값으로 갖지 않는다.

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

enum 타입의 변수를 선언할 때는 CompassPoint.east 라고 해도 되고 goEast 처럼 이미 타입을 지정한 경우는 .east 만써도 컴파일러가 알게 된다

var goSouth: CompassPoint = CompassPoint.south    
var goEast: CompassPoint = .east                    

위에서 지정한 값을 print하면 각각 south, east 가 찍히게 된다
결국 별도 값을 지정하지 않아도 이름이 값이 된다는 사실을 알 수 있다

print(goSouth)        // Prints south
print(goEast)        // Prints east

Enum initialize raw value

그럼 값을 지정하려면 어떻게 하나?
swift enum에는 rawValue(원시값) 을 사용하여 값을 초기화할 수 있다

예를 들어 아래와 같이 CompassPoint 가 Int 값을 가지게 한다면 순서대로 0~3 의 값을 갖는다
중간에 생략해도 알아서 값이 초기화된다. 순서대로 말고 각 다른 값을 넣을거라면 각각 값으로 초기화한다.

enum CompassPoint: Int {
    case north = 1    // 첫 번째 값에 1이 대입되어 밑은 2, 3, 4 로 대입된다
    case south
    case east
    case west
}

Int 는 순서가 명확하게 0 1 2 로 되지만 0.0 으로 초기화한다면 0.0다음에 0.1이 올지, 1.1이 올지, 0.01이 올지 컴파일러는 판단할 수 없다
그런 값은 각 case 별로 초기화가 필요하다

만일 “A”로 초기화하면 어떻게 될까? B, C, D 순으로 될까?

enum CompassPoint: String {
    case north
    case south
    case east = "E"
    case west
}

var goSouth: CompassPoint = CompassPoint.south
var goEast: CompassPoint = .east

print(goSouth.rawValue)        // Prints south
print(goEast.rawValue)        // Prints E

이미 CompassPoint.south가 string이므로 이름이 값으로 초기화된다


Associated Values (연관값)

각 하나의 타입에 대해 인스턴스마다 다른 값을 가지게 할 때 사용한다

Swift 공식 문서에는 바코드 예제로 이것을 설명한다
1.바코드는 크게 1차원 바코드와 2차원 바코드인 QR코드로 나뉜다.
2.1차원 바코드는 12자리 숫자를 표현한다
3.2차원 바코드는 임의의 문자열을 표현할 수 있다

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

var productBarcode = Barcode.upc(8, 1434, 34324, 3)

productBarcode = .qrCode("ADSFAFDASDF")
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
    print("UPC \(numberSystem) \(manufacturer) \(product) \(check)")
case .qrCode(let productCode):
    print("QR \(productCode)")
}

Switch case + enum

switch case에 enum을 결합해서 사용하면 enum에서 생성한 case에 대해서만 분기를 탈 수 있게 한다
이 경우는 switch case 의 default 는 실행되지 않기 때문에 @unknown default: 을 추가하여 할당되지 않은 값이 들어올 때 처리를 할 수 있다

switch goEast {
case .north:
    print("let's go north")
case .south:
    print("let's go south")
case .east:
    print("let's go east")
case .west:
    print("let's go west")
@unknown default:
    print("I can't go anywhere")
}

Iterating over Enumeration Cases

Enum에는 CaseIterable protocol을 채택할 수 있다. allCases 로 값 모음에 접근할 수 있다
모든 항목에 접근할 수 있다는 말

var directions = CompassPoint.allCases.count
print("In the Earth have \(directions) directions")

allCases 로 enum의 모든 case에 쉽게 접근할 수 있다

for direction in CompassPoint.allCases {
    print(direction)
}

let _ = CompassPoint.allCases.map {print($0)}

CaseIterable (protocol)

A type that provides a collection of all of its values.

위에서 나온 CaseIterable 프로토콜을 살펴보자.
이 프로토콜은 enum에서 주로 사용한다. allCases 속성을 사용 해 모든 케이스에 접근할 수 있다

반응형