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

원시 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



답변

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)
}

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


답변

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

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"
      }
    }
  }
}


답변

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 열거 형에서만 작동합니다.


답변

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)


답변

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에 정의되어 있으므로 위와 같이 작동하지 않습니다.


답변

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


답변

너무 실망 스럽습니다.

그러한 이름이 필요한 경우 (컴파일러는 정확한 철자를 완벽하게 알고 있지만 액세스를 거부합니다-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!