ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Enumerations
    iOS/Swift 공식문서 2022. 2. 16. 22:32

    Enumeration Syntax

    enum 키워드를 사용하여 열거형을 정의할 수 있다.

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

     

    여러 case를 콤마로 구분하여 나열할 수 있다.

    enum Planet {
        case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
    }

     

    note

    Swift의 경우 열거형의 case들이 정수값을 가지지 않는다. 대신 case들은 해당 열거형 타입(ex. CompassPoint, Planet 등)으로 선언된 온전한 값이다.

     

    각 열거형 정의는 새로운 타입을 정의한다. 따라서 Swift의 다른 타입처럼, 열거형의 이름은 대문자로 시작해야 한다. 아래 예시에서 directionToHead라는 변수는 타입 추론을 통해 CompassPoint 타입을 갖게 된다.

    var directionToHead = CompassPoint.west

     

    타입이 이미 정해진 이후에는 다음과 같이 타입을 생략할 수 있다.

    directionToHead = .east

     

    Matching Enumeration Values with a Switch Statement

    열거형의 값을 switch문에서 사용할 수 있다. switch 문은 값의 모든 case를 다 포함해야 하기 때문에 열거형의 값 중 하나라도 빠져 있다면 컴파일되지 않는다.

    directionToHead = .south
    switch directionToHead {
    case .north:
        print("Lots of planets have a north")
    case .south:
        print("Watch out for penguins")
    case .east:
        print("Where the sun rises")
    case .west:
        print("Where the skies are blue")
    }
    // Prints "Watch out for penguins"

     

    아래와 같이 여러 값들을 default로 처리하는 방법도 있다.

    let somePlanet = Planet.earth
    switch somePlanet {
    case .earth:
        print("Mostly harmless")
    default:
        print("Not a safe place for humans")
    }
    // Prints "Mostly harmless"

     

    Iterating over Enumeration Cases

    열거형 정의 시 CaseIterable 키워드를 사용하면 allCases 프로퍼티를 통하여 모든 값의 컬렉션을 사용할 수 있다. 이 경우 열거형은 CaseIterable 프로토콜을 따르게 된다.

    enum Beverage: CaseIterable {
        case coffee, tea, juice
    }
    
    let numberOfChoices = Beverage.allCases.count
    print("\(numberOfChoices) beverages available")
    // Prints "3 beverages available"
    
    for beverage in Beverage.allCases {
        print(beverage)
    }
    // coffee
    // tea
    // juice

     

    Associated Values

    열거형의 각 case에 대하여 추가적인 정보를 저장할 수 있는데, 이 추가적인 정보를 관련 값(associated value)이라고 한다. 예를 들어 바코드가 4개의 정수값으로 이루어진 upc와, 문자들로 구성된 QR코드 2종류로 나뉜다면, 바코드를 다음과 같은 열거형으로 정의할 수 있다. 이와 같이 같은 타입이지만 다른 형태의 값을 가지는 case를 만들 수 있다.

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

     

    UPC, QR코드는 아래와 같이 선언할 수 있다.

    var productBarcode = Barcode.upc(8, 85909, 51226, 3)
    productBarcode = .qrCode("ABCDEFGHIJKLMNOP")

     

    관련 값은 switch case 문에서 상수/변수로 선언할 수 있다.

    switch productBarcode {
    case .upc(let numberSystem, let manufacturer, let product, let check):
        print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
    case .qrCode(let productCode):
        print("QR code: \(productCode).")
    }
    // Prints "QR code: ABCDEFGHIJKLMNOP."

     

    Raw Values

    열거형의 case는 기존 타입의 raw 값을 가질 수 있다. case의 값은 모두 같은 타입이어야 한다.

    enum ASCIIControlCharacter: Character {
        case tab = "\t"
        case lineFeed = "\n"
        case carriageReturn = "\r"
    }

     

    Implicitly Assigned Raw Values

    정수나 문자열을 raw 값으로 사용할 경우 각 case에 대하여 명시적으로 raw 값을 할당할 필요가 없다. 정수를 raw 값으로 사용하는 경우 각 case의 암시적 값은 이전 case 값보다 1만큼 큰 값이다. 첫번째 case의 경우 값을 명시하지 않으면 0으로 설정된다.

    enum Planet: Int {
        case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    }

     

    문자열이 사용될 경우, 각 case 이름의 문자열이 raw 값이 된다. raw 값은 rawValue 프로퍼티로 접근할 수 있다.

    enum CompassPoint: String {
        case north, south, east, west
    }
    
    let sunsetDirection = CompassPoint.west.rawValue
    // sunsetDirection is "west"

     

    Initializing from a Raw Value

    열거형을 raw 값으로 정의한 경우, raw 값으로 사용한 타입의 값을 받는 initializer를 사용할 수 있다. 해당 값을 가지는 case가 존재하면 해당 case를 반환하고, 없으면 nil을 반환한따. nil을 반환할 수 있기 때문에 타입은 optional이다. case를 반환하지 못할 수 있기 때문에 failable initializer라고 부른다.

    let possiblePlanet = Planet(rawValue: 7)
    // possiblePlanet is of type Planet? and equals Planet.uranus
    
    let positionToFind = 11
    if let somePlanet = Planet(rawValue: positionToFind) {
        switch somePlanet {
        case .earth:
            print("Mostly harmless")
        default:
            print("Not a safe place for humans")
        }
    } else {
        print("There isn't a planet at position \(positionToFind)")
    }
    // Prints "There isn't a planet at position 11"

     

    Recursive Enumerations

    최소 한 개의 case에서 관련 값으로 다른 열거형 인스턴스를 가지는 열거형을 말한다. 해당 caseindirect라는 키워드를 적어서 재귀적인 case임을 나타낸다.

    enum ArithmeticExpression {
        case number(Int)
        indirect case addition(ArithmeticExpression, ArithmeticExpression)
        indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
    }

     

    모든 case에 indirect 표시를 하고 싶으면 enum 키워드 앞에 indirect 키워드를 적는 방법도 있다.

    indirect enum ArithmeticExpression {
        case number(Int)
        case addition(ArithmeticExpression, ArithmeticExpression)
        case multiplication(ArithmeticExpression, ArithmeticExpression)
    }
    
    let five = ArithmeticExpression.number(5)
    let four = ArithmeticExpression.number(4)
    let sum = ArithmeticExpression.addition(five, four)
    let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

    이러한 재귀 열거형은 재귀적인 구조를 갖는 데이터를 다룰 때 유용하다.

    func evaluate(_ expression: ArithmeticExpression) -> Int {
        switch expression {
        case let .number(value):
            return value
        case let .addition(left, right):
            return evaluate(left) + evaluate(right)
        case let .multiplication(left, right):
            return evaluate(left) * evaluate(right)
        }
    }
    
    print(evaluate(product))
    // Prints "18"

     

    Reference

    https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html

    'iOS > Swift 공식문서' 카테고리의 다른 글

    Properties  (0) 2022.02.18
    Structures and Classes  (0) 2022.02.17
    Closures  (0) 2022.02.16
    Functions  (0) 2022.02.15
    Control Flow  (0) 2022.02.15

    댓글

Designed by Tistory.