[Xcode / Swift] 열거형 rawValue과 암시적 맴버 표현으로 인한 생략(.)| Enumeration, rawValue

Enumeration은 열거형 자료형 표현으로 기타 다른 언어들에서도 쉽게 찾아볼 수 있는 친구이다. 뭐든 공식 문서를 찾아 보는 것이 좋으니, 아래 공식 문서의 정의를 살펴보자.

열거형은 관련된 값의 그룹에 대한 공통 유형을 정의하며 코드에서 유형이 안전한 방식으로 해당 값으로 작업 할 수 있게 한다. 또한, raw Value라고 알려진 값이 각각의 enum case에 제공되어 string, character 혹은 integer, floating-point 값으로도 될 수 있다.”

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.

If you are familiar with C, you will know that C enumerations assign related names to a set of integer values. Enumerations in Swift are much more flexible, and do not have to provide a value for each case of the enumeration. If a value (known as a “raw” value) is provided for each enumeration case, the value can be a string, a character, or a value of any integer or floating-point type.

출처 – The Swift Programming Language (Swift 4.1)


rawValue

그렇다면 그 rawValue가 어떻게 사용되는지를 알아보자.

우선, enum 친구는 아래와 같이 case로 나눠 사용할 수 있으며, 한줄에 몽땅 적을 수도 있다.

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

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

위 두 코드는 같은 내용을 나타는 것으로 관련된 값 혹은 가독성에 의해 본인이 스스로 적절히 나누어 주면 된다.

enum은 마치 Class가 상속을 받는 것처럼 Raw Type을 정의할 수 있는데, 아래의 예제는 PaperSize 열거형을 String으로 정의하였다. ‘아니, selectedSize를 print하나 selectedSize.rawValue를 print하나 값이 똑같은데?’라고 말할 수 있다. 하지만, 그 자료형을 보면 차이가 난다.

enum PaperSize: String {
    case A4, A5, Letter, Legal
}

let selectedSize = PaperSize.Letter
print(selectedSize.rawValue)
// Prints "Letter"

아래 두가지 예시를 보면 하나는 String 하나는 PaperSize 타입인 것을 알 수 있다. 고로, 열거형을 raw형의 자료형과 비교할 땐 rawValue를 꼭 써주어야 한다.

type(of: selectedSize) //PaperSize.Type
type(of: selectedSize.rawValue) //String.Type

selectedSize == "Letter" //오류
selectedSize.rawValue == "Letter" //true

Value Association

enum의 또 다른 강력한 기능 중 하나는 Value Association이다. 아래 예제를 보면, PaperSize에 기본 rawValue를 선언해주지 않고, case에 서로 다른 두 Biding(A4(Int,Int), Letter(Int))가 존재한다. 이로써 어떠한 형태의 다른 값이라도 enum의 각각의 case에 독립적으로 연동될 수 있다는 점이다.

enum PaperSize{
    case A4(width :Int, height :Int), A5, Letter(count: Int)
    
    func desc() -> String
    {
        switch(self) {
        case let .A4(width, height):
            return "Width is \(width), Heigh is \(height)"
        case let .Letter(count):
            return "Total \(count) Letter(s)"
        default :
            return "Quit"
        }
    }
}

let paperA4 = PaperSize.A4(width :210, height :297)
let paperLetter = PaperSize.Letter(count: 1)

paperA4.desc() //"Width is 210, Heigh is 297"
paperLetter.desc() //"Total 1 Letter(s)"

암시적 맴버 생략

한글로 어떻게 표현해야할지 모르겠지만, 이 내용은 Implicit Member Expression과 유관하다. 처음 Swift를 공부하다 보면, 아래와 같이 뜬금 없이 .medium과 같은 값이 나오는 경우를 볼 수 있다. 이는 뒤에서 쓰일 medium 앞의 자료형이 DateFormatter.Style로 이미 dataFormatter.dateStyle의 자료형과 같기 때문에 생략해준 것이다. 주로 enum case나 class의 method를 접근할 때 다음과 같이 생략한다.

let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .none

그래서 위의 .medium은 DateFormatter.Style.medium과 같은 것이다.

마지막으로 아래와 같이 [.hour, .minute, .second]로 넘겨주는 것이 어떻게 가능할까.

import UIKit

let date = Date()
let calendar = Calendar.current

let components = calendar.dateComponents([.hour,.minute,.second], from: date)
  1.  dataComponents 함수는 Set<Calendar.Component> 즉, Calendar 구조체의 Component enum형을 받을 수 있게 이미 명시가 되어 있다.
  2. 즉, [.hour, .minute, .second]의 의미는 [Calendar.Component.hour, Calendar.Component.minute, Calendar.Component.second]와 같다.

아래 두 공식 문서를 참조해보면 쉽게 알 수 있다.


참조

댓글 남기기