How to get the name of enumeration value in Swift?
As of Xcode 7 beta 5 (Swift version 2) you can now print type names and enum cases by default using print(_:)
, or convert to String
using String
's init(_:)
initializer or string interpolation syntax. So for your example:
enum City: Int { case Melbourne = 1, Chelyabinsk, Bursa}let city = City.Melbourneprint(city)// prints "Melbourne"let cityName = "\(city)" // or `let cityName = String(city)`// cityName contains "Melbourne"
So there is no longer a need to define & maintain a convenience function that switches on each case to return a string literal. In addition, this works automatically for any enum, even if no raw-value type is specified.
debugPrint(_:)
& String(reflecting:)
can be used for a fully-qualified name:
debugPrint(city)// prints "App.City.Melbourne" (or similar, depending on the full scope)let cityDebugName = String(reflecting: city)// cityDebugName contains "App.City.Melbourne"
Note that you can customise what is printed in each of these scenarios:
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)"
(I haven't found a way to call into this "default" value, for example, to print "The city is Melbourne" without resorting back to a switch statement. Using \(self)
in the implementation of description
/debugDescription
causes an infinite recursion.)
The comments above String
's init(_:)
& init(reflecting:)
initializers describe exactly what is printed, depending on what the reflected type conforms to:
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)}
See the release notes for info about this change.
There is no introspection on enum cases at the moment. You will have to declare them each manually:
enum City: String, CustomStringConvertible { case Melbourne = "Melbourne" case Chelyabinsk = "Chelyabinsk" case Bursa = "Bursa" var description: String { get { return self.rawValue } }}
If you need the raw type to be an Int, you will have to do a switch yourself:
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" } } }}
In Swift-3 (tested with Xcode 8.1) you can add the following methods in your enum:
/** * 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) }}
You can then use it as a normal method call on your enum instance.It might also work in previous Swift versions, but I haven't tested it.
In your example:
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.Melbourneprint(city.name)// prints "Melbourne"print(city.description)// prints "City.Melbourne"
If you want to provide this functionality to all your enums, you can make it an extension:
/** * 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) } }}
This only works for Swift enums.