如何获得斯威夫特枚举值的名字吗?

问题描述 投票:138回答:9

如果我有一个原始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
swift enumeration
9个回答
119
投票

作为Xcode的7测试版5(SWIFT第2版),你可以在默认情况下使用print(_:)现在打印类型名称和枚举的情况下,或将使用StringString初始化或字符串插补语法init(_:)。因此,对于你的例子:

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

(我还没有找到一个方法来调用这个“默认”值,例如,要打印“城市是墨尔本”不诉诸回到switch语句。在\(self)执行/ description导致无限循环使用debugDescription。 )

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

请参阅有关这一变化信息的release notes


1
投票

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的类型产生斯威夫特接口有时不包括@objc修改。那些被枚举在Objective-C仍然定义,并且因此不象上述方式工作。


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

32
投票

在斯威夫特-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) }
}

然后,您可以使用它作为你的枚举实例正常的方法调用。它也可能在以前的版本中雨燕的工作,但我没有测试它。

在您的例子:

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

这仅适用于斯威夫特枚举。


16
投票

对于Objective-C的enums目前唯一的办法似乎是,例如,延长与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"
        }
    }
}

然后铸造enumString

String(UIDevice.currentDevice().batteryState)

7
投票

关于字符串(...)在雨燕2.2枚举(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(嘘豪)。

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

与反射的情况应该是斯威夫特3后渐入佳境,显然。现在的解决方案,虽然是String(…),在其他的答案中的一个建议:

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

5
投票

这是如此令人失望。

因为当你需要这些名称的情况下(编译器非常了解的准确拼写,但拒绝让访问 - 谢谢你斯威夫特团队!! - ),但不想或不能使你的字符串枚举的基地,冗长,繁琐的替代方法是如下:

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


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

2
投票

简单,但工程...

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

2
投票

斯威夫特现在有所谓的Implicitly Assigned Raw Value。基本上,如果你不给每个案件给的原始值和枚举的类型为String,它推断的情况下的原始值本身是字符串格式。去试试看。

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

let city = City.Melbourne.rawValue

// city is "Melbourne"
© www.soinside.com 2019 - 2024. All rights reserved.