Swift에서 열거 형 값의 이름을 얻는 방법은 무엇입니까?


167

원시 Integer값으로 열거 형이있는 경우 :

enum City: Int {
  case Melbourne = 1, Chelyabinsk, Bursa
}

let city = City.Melbourne

city값을 문자열 로 어떻게 변환 Melbourne합니까? 이런 종류의 이름 내성 검사가 언어로 제공됩니까?

다음과 같은 것 (이 코드는 작동하지 않습니다) :

println("Your city is \(city.magicFunction)")
> Your city is Melbourne

답변:


139

Xcode 7 베타 5 (Swift 버전 2)부터는 기본적으로을 사용하여 유형 이름과 열거 형 케이스를 인쇄 print(_:)하거나 의 이니셜 라이저 또는 문자열 보간 구문 을 String사용하여 변환 할 수 있습니다. 예를 들어 :Stringinit(_:)

enum City: Int {
    case Melbourne = 1, Chelyabinsk, Bursa
}
let city = City.Melbourne

print(city)
// prints "Melbourne"

let cityName = "\(city)"   // or `let cityName = String(city)`
// cityName contains "Melbourne"

따라서 더 이상 문자열 리터럴을 리턴하기 위해 각 케이스를 전환하는 편의 기능을 정의하고 유지 보수 할 필요가 없습니다. 또한 이는 원시 값 유형이 지정되지 않은 경우에도 모든 열거 형에 대해 자동으로 작동합니다.

debugPrint(_:)& String(reflecting:)는 완전한 이름으로 사용될 수 있습니다 :

debugPrint(city)
// prints "App.City.Melbourne" (or similar, depending on the full scope)

let cityDebugName = String(reflecting: city)
// cityDebugName contains "App.City.Melbourne"

다음 각 시나리오에서 인쇄되는 내용을 사용자 정의 할 수 있습니다.

extension City: CustomStringConvertible {
    var description: String {
        return "City \(rawValue)"
    }
}

print(city)
// prints "City 1"

extension City: CustomDebugStringConvertible {
    var debugDescription: String {
        return "City (rawValue: \(rawValue))"
    }
}

debugPrint(city)
// prints "City (rawValue: 1)"

(이 스위치 값에 의존하지 않고 "도시는 멜버른"으로 인쇄하는 것과 같이이 "기본"값을 호출하는 방법을 찾지 못했습니다. / \(self)구현에 사용 하면 무한 재귀가 발생합니다.)descriptiondebugDescription


Stringinit(_:)& init(reflecting:)이니셜 라이저는 반영된 유형이 준수하는 내용에 따라 인쇄되는 내용을 정확하게 설명합니다.

extension String {
    /// Initialize `self` with the textual representation of `instance`.
    ///
    /// * If `T` conforms to `Streamable`, the result is obtained by
    ///   calling `instance.writeTo(s)` on an empty string s.
    /// * Otherwise, if `T` conforms to `CustomStringConvertible`, the
    ///   result is `instance`'s `description`
    /// * Otherwise, if `T` conforms to `CustomDebugStringConvertible`,
    ///   the result is `instance`'s `debugDescription`
    /// * Otherwise, an unspecified result is supplied automatically by
    ///   the Swift standard library.
    ///
    /// - SeeAlso: `String.init<T>(reflecting: T)`
    public init<T>(_ instance: T)

    /// Initialize `self` with a detailed textual representation of
    /// `subject`, suitable for debugging.
    ///
    /// * If `T` conforms to `CustomDebugStringConvertible`, the result
    ///   is `subject`'s `debugDescription`.
    ///
    /// * Otherwise, if `T` conforms to `CustomStringConvertible`, the result
    ///   is `subject`'s `description`.
    ///
    /// * Otherwise, if `T` conforms to `Streamable`, the result is
    ///   obtained by calling `subject.writeTo(s)` on an empty string s.
    ///
    /// * Otherwise, an unspecified result is supplied automatically by
    ///   the Swift standard library.
    ///
    /// - SeeAlso: `String.init<T>(T)`
    public init<T>(reflecting subject: T)
}


이 변경에 대한 정보 는 릴리스 정보 를 참조하십시오 .


8
또한 사용하지 않고 문자열 값을 원하면 print(enum)다음을 사용할 수 있습니다.String(enum)
Kametrixom

44
중요한 catch 는 Swift 열거 형 에만 적용됩니다. OS X에서 바인딩 지원을 허용하기 위해 @objc 태그를 지정하면 작동하지 않습니다.
Claus Jørgensen

11
위대한 스위프트 관련 답변; 그러나 델리게이트 콜백 CLAuthorizationStatus내에 (Objective C) 열거 형 값 을 인쇄하는 것과 같이 신속하지 않은 열거 형 에서이 작업을 수행 해야하는 경우 locationManager didChangeAuthorizationStatus프로토콜 확장을 정의해야합니다. 예를 들면 다음과 같습니다 extension CLAuthorizationStatus: CustomStringConvertable { public var description: String { switch self { case .AuthorizedAlways: return "AuthorizedAlways" <etc> } } }.-일단이 작업을 수행하면 예상대로 작동합니다 : print ( "Auth status : (\ status))".
Jeffro

3
"Xcode 7 베타 5 기준"은 의미가 없습니다. 이것을 정의하는 것은 Xcode가 아니며 Swift 컴파일러와 Swift Runtime Library입니다. Xcode 9.3을 사용할 수 있지만 내 코드는 여전히 Swift 3 일 수 있으며 Swift 4 기능을 사용할 수 없습니다. Xcode 9.3을 사용하면 Xcode 9.3이 Xcode 7보다 훨씬 최신 버전이지만이 코드는 작동하지 않습니다.
Mecki

8
초기화 프로그램 'init (_ :)'에 City가 xcode 10.2, Swift 5의 'LosslessStringConvertible'을 준수해야합니다. 지금 어떻게해야합니까?
rockgecko

73

현재 열거 형 사례에 대한 내성은 없습니다. 각각 수동으로 선언해야합니다.

enum City: String, CustomStringConvertible {
    case Melbourne = "Melbourne"
    case Chelyabinsk = "Chelyabinsk"
    case Bursa = "Bursa"

    var description: String {
        get {
            return self.rawValue
        }
    }
}

원시 유형이 Int가되어야하는 경우 직접 스위치를 수행해야합니다.

enum City: Int, CustomStringConvertible {
  case Melbourne = 1, Chelyabinsk, Bursa

  var description: String {
    get {
      switch self {
        case .Melbourne:
          return "Melbourne"
        case .Chelyabinsk:
          return "Chelyabinsk"
        case .Bursa:
          return "Bursa"
      }
    }
  }
}

2
멍청한 질문이지만, 왜 self.value를 반환하는 대신 get {return self.rawValue}를 넣습니까? 나는 후자를 시도했지만 정상적으로 작동합니다.
Chuck Krutsinger

get { ... }세터를 정의하지 않으면 간결성을 위해 파트를 생략 할 수도 있습니다 .
iosdude

1
큰 답변 주셔서 감사합니다. Xcode 7.3에서 "Printable의 이름이 CustomStringConvertible로 바뀌 었습니다"라는 메시지가 나타납니다. 해결책은 위의 첫 번째 코드 예에서 첫 번째 행을로 변경하는 것 enum City : String, CustomStringConvertible {입니다. CSC 프로토콜의 일부로, 다음과 같이 속성을 public 으로 변경해야합니다 .public var description : String {
Jeffro

44

Swift-3 (Xcode 8.1로 테스트)에서 열거 형에 다음 메소드를 추가 할 수 있습니다.

/**
 * The name of the enumeration (as written in case).
 */
var name: String {
    get { return String(describing: self) }
}

/**
 * The full name of the enumeration
 * (the name of the enum plus dot plus the name as written in case).
 */
var description: String {
    get { return String(reflecting: self) }
}

그런 다음 열거 형 인스턴스에서 일반적인 메소드 호출로 사용할 수 있습니다. 이전 Swift 버전에서도 작동하지만 테스트하지는 않았습니다.

귀하의 예에서 :

enum City: Int {
    case Melbourne = 1, Chelyabinsk, Bursa
    var name: String {
        get { return String(describing: self) }
    }
    var description: String {
        get { return String(reflecting: self) }
    }
}
let city = City.Melbourne

print(city.name)
// prints "Melbourne"

print(city.description)
// prints "City.Melbourne"

이 기능을 모든 열거 형에 제공하려는 경우이를 확장으로 만들 수 있습니다.

/**
 * Extend all enums with a simple method to derive their names.
 */
extension RawRepresentable where RawValue: Any {
  /**
   * The name of the enumeration (as written in case).
   */
  var name: String {
    get { return String(describing: self) }
  }

  /**
   * The full name of the enumeration
   * (the name of the enum plus dot plus the name as written in case).
   */
  var description: String {
    get { return String(reflecting: self) }
  }
}

이것은 Swift 열거 형에서만 작동합니다.


18

Objective-C enum의 경우 현재 예를 들어 CustomStringConvertible다음과 같이 끝나는 열거 형을 확장하는 유일한 방법 인 것 같습니다.

extension UIDeviceBatteryState: CustomStringConvertible {
    public var description: String {
        switch self {
        case .Unknown:
            return "Unknown"
        case .Unplugged:
            return "Unplugged"
        case .Charging:
            return "Charging"
        case .Full:
            return "Full"
        }
    }
}

그런 다음 enumas 를 캐스팅하십시오 String.

String(UIDevice.currentDevice().batteryState)

12

String(describing:)초기화 심지어 비 문자열 rawValues와 열거 형의 경우 레이블 이름을 반환 할 수 있습니다 :

enum Numbers: Int {
    case one = 1
    case two = 2
}

let one = String(describing: Numbers.one) // "one"
let two = String(describing: Numbers.two) // "two"

이 점에 유의 작동하지 않습니다 열거가 사용하는 경우 @objc수정을 :

https://forums.swift.org/t/why-is-an-enum-returning-enumname-rather-than-caselabel-for-string-describing/27327

Objective-C 유형에 대해 생성 된 Swift 인터페이스에는 때때로 @objc수정자가 포함되지 않습니다 . 그럼에도 불구하고 이러한 열거 형은 Objective-C에 정의되어 있으므로 위와 같이 작동하지 않습니다.


7

Swift 2.2에서 열거 형에 대한 String (…) (CustomStringConvertible) 지원 외에도 약간의 리플렉션 지원이 있습니다. 관련 값이있는 열거 형 케이스의 경우 리플렉션을 사용하여 열거 형 케이스의 레이블을 가져올 수 있습니다.

enum City {
    case Melbourne(String)
    case Chelyabinsk
    case Bursa

    var label:String? {
        let mirror = Mirror(reflecting: self)
        return mirror.children.first?.label
    }
}

print(City.Melbourne("Foobar").label) // prints out "Melbourne"

그러나 깨져서 "단순한"열거 형의 경우 위의 반사 기반 label계산 속성은 nil(boo-hoo)를 반환합니다 .

print(City.Chelyabinsk.label) // prints out nil

Swift 3 이후에는 반성이있는 상황이 좋아질 것입니다. String(…)다른 답변 중 하나에서 제안한 것처럼 지금의 해결책은입니다 .

print(String(City.Chelyabinsk)) // prints out Cheylabinsk

2
이것은 선택 사항으로 만들 필요없이 Swift 3.1에서 작동하는 것 같습니다 :var label:String { let mirror = Mirror(reflecting: self); if let label = mirror.children.first?.label { return label } else { return String(describing:self) } }
David James

5

너무 실망 스럽습니다.

그러한 이름이 필요한 경우 (컴파일러는 정확한 철자를 완벽하게 알고 있지만 액세스를 거부합니다-Swift 팀 감사합니다 !!)-String을 열거 형의 기초로 만들고 싶지는 않습니다. 장황하고 번거로운 대안은 다음과 같습니다.

enum ViewType : Int, Printable {

    case    Title
    case    Buttons
    case    View

    static let all = [Title, Buttons, View]
    static let strings = ["Title", "Buttons", "View"]

    func string() -> String {
        return ViewType.strings[self.rawValue]
    }

    var description:String {
        get {
            return string()
        }
    }
}

위와 같이 사용할 수 있습니다 :

let elementType = ViewType.Title
let column = Column.Collections
let row = 0

println("fetching element \(elementType), column: \(column.string()), row: \(row)")

그리고 예상 결과를 얻습니다 (열의 코드는 비슷하지만 표시되지는 않음)

fetching element Title, column: Collections, row: 0

위에서, 나는 description속성이 string방법을 다시 참조하도록 만들었지 만 이것은 맛의 문제입니다. 또한 static컴파일러는 너무 기억 상실하고 컨텍스트 자체를 리콜 할 수 없으므로 소위 변수는 엔 클로징 유형의 이름으로 범위를 한정해야합니다.

스위프트 팀은 반드시 지휘해야합니다. 그들은 당신이 할 수없는 열거 생성 enumerate되는 것을 사용할 수 enumerate있지만 페이지의 "시퀀스"됩니다 enum!


설명에서 반환 문자열 (반영 : self)을 수행하는 것보다 오히려 오래 걸리는 것 같습니다.

4

나는이 질문에 부딪 쳤고 마술을 만드는 간단한 방법을 공유하고 싶었습니다.

enum City: Int {
  case Melbourne = 1, Chelyabinsk, Bursa

    func magicFunction() -> String {
        return "\(self)"
    }
}

let city = City.Melbourne
city.magicFunction() //prints Melbourne

3

스위프트는 이제 암시 적으로 할당 된 미가공 가치를 가지고 있습니다. 기본적으로 각 사례에 원시 값을 제공하지 않고 열거 형이 String 유형 인 경우 사례의 원시 값 자체가 문자열 형식 인 것으로 추론됩니다. 시도해보십시오.

enum City: String {
  case Melbourne, Chelyabinsk, Bursa
}

let city = City.Melbourne.rawValue

// city is "Melbourne"

3

스위프트

extension UIDeviceBatteryState: CustomStringConvertible {

    public var description: String {
        switch self {
        case .unknown:
            return "unknown"
        case .unplugged:
            return "unplugged"
        case .charging:
            return "charging"
        case .full:
            return "full"
        }
    }

}

변수 "batteryState"인 경우 다음을 호출하십시오.

self.batteryState.description

1

간단하지만 작동합니다 ...

enum ViewType : Int {
    case    Title
    case    Buttons
    case    View
}

func printEnumValue(enum: ViewType) {

    switch enum {
    case .Title: println("ViewType.Title")
    case .Buttons: println("ViewType.Buttons")
    case .View: println("ViewType.View")
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.