如何在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
128506 次浏览

目前在枚举情况下没有自省。你必须手动声明它们:

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团队!!——)但不想或不能让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!

简单但有效…

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

从Xcode 7 beta 5 (Swift版本2)开始,你现在可以默认使用print(_:)打印类型名和枚举大小写,或者使用Stringinit(_:)初始化器或字符串插值语法转换为String。举个例子:

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语句。在description/debugDescription的实现中使用\(self)会导致无限递归。)

< p > < br > 上面的注释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)
}
< p > < br > 有关此更改的信息,请参阅发布说明

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

然后将enum转换为String:

String(UIDevice.currentDevice().batteryState)

Swift现在有所谓的隐式赋值。基本上,如果您不为每个case提供原始值,并且枚举类型为String,则它推断出case的原始值本身为字符串格式。去试试吧。

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


let city = City.Melbourne.rawValue


// city is "Melbourne"

在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 computed属性只返回nil (boo-hoo)。

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

显然,在《Swift 3》之后,反思的情况应该会有所好转。现在的解决方案是String(…),正如在其他答案之一中所建议的那样:

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

在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枚举。

迅速:

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

String(describing:)初始化式可用于返回大小写标签名称,即使是枚举的rawValues为非string类型:

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


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

注意,如果枚举使用@objc修饰符,则此不起作用:

为Objective-C类型生成的Swift接口有时不包括@objc修饰符。这些枚举是在Objective-C中定义的,因此不像上面那样工作。

我遇到了这个问题,想分享一个创建magicFunction的简单方法

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


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


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

内省在快速枚举似乎部分工作。

我看到了@drewag的回复,发现一个没有rawValues的Enum确实可以在Swift 5中进行自省。X与Xcode 11.5。这段代码可以工作。

public enum Domain: String {
case network
case data
case service
case sync
var description: String {
return "\(self)"     // THIS INTROSPECTION WORKS
}
}
enum ErrorCode: Int, CustomStringConvertible {
case success = 200
case created = 201
case accepted = 202
case badRequest = 400
case unauthorized = 401
case forbidden = 403
case notFound = 404
var code: Int {
return self.rawValue
}
var description: String {
return "\(self)"      //THIS DOES NOT WORK - EXEC_BAD_ACCESS
}
}
let errorCode = ErrorCode.notFound
let domain = Domain.network
print(domain.description, errorCode.code, errorCode.description)
将第二个Enum中的"string"替换为"\(self)",你将得到以下打印输出: 网络404字符串

注意:使用String(self)而不是"\(self)" in the first Enumwill require the Enum to conform to theLosslessStringConvertible协议,并添加其他初始化器,因此字符串插值似乎是一个很好的解决方案。

要将var description: String添加到枚举中,必须使用Switch语句将前面指出的所有枚举情况添加到枚举中

var description: String {
switch self {
case .success: return "Success"
case .created: return "Created"
case .accepted: return "Accepted"
}
}