How to get the name of enumeration value in Swift?

SwiftEnumeration

Swift Problem Overview


If I have an enumeration with raw Integer values:

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

let city = City.Melbourne

How can I convert a city value to a string Melbourne? Is this kind of a type name introspection available in the language?

Something like (this code will not work):

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

Swift Solutions


Solution 1 - 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.Melbourne

print(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.

Solution 2 - Swift

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

Solution 3 - Swift

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.Melbourne

print(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.

Solution 4 - Swift

The String(describing:) initializer can be used to return the case label name even for enums with non-String rawValues:

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

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

Note that this does not work if the enum uses the @objc modifier:

Generated Swift interfaces for Objective-C types sometimes do not include the @objc modifier. Those Enums are nevertheless defined in Objective-C, and thus do not work like above.

Solution 5 - Swift

For Objective-C enums the only way currently seems to be, for example, to extend the enum with CustomStringConvertible ending up with something like:

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

And then casting the enum as String:

String(UIDevice.currentDevice().batteryState)

Solution 6 - Swift

On top of the String(…) (CustomStringConvertible) support for enums in Swift 2.2, there's also somewhat broken reflection support for them. For enum cases with associated values it is possible to get the label of the enum case using reflection:

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"

By being broken, I however meant that for "simple" enums, the above reflection based label computed property just returns nil (boo-hoo).

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

The situation with reflection should be getting better after Swift 3, apparently. The solution for now though is String(…), as suggested in one of the other answers:

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

Solution 7 - Swift

I bumped into this question and wanted to share a simple way to create the magicFunction mentioned

enum City: Int {
  case Melbourne = 1, Chelyabinsk, Bursa
    
    func magicFunction() -> String {
        return "\(self)"
    }
}

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

Solution 8 - Swift

This is so disappointing.

For the case when you need those names (that the compiler perfectly knows the exact spelling of, but refuses to let access -- thank you Swift team!! --) but do not want or cannot make String the base of your enum, a verbose, cumbersome alternative is as follows:

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

You can use the above as follows:

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

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

And you'll get the expected result (code for the Column similar, but not shown)

fetching element Title, column: Collections, row: 0

In the above, I have made the description property refer back to the string method, but this is a matter of taste. Also note that so called static variables need to be scope qualified by the name of their enclosing type, as the compiler is too amnesic and cannot recall the context all by itself...

The Swift team must really be commanded. They created enum that you cannot enumerate and that which you can use enumerate on are "Sequences" but not enum!

Solution 9 - Swift

Swift now has what are known as Implicitly Assigned Raw Value. Basically if you don't give raw values to each case and the enum is of type String, it deduces that the case's raw value is itself in string format. Go on give it a try.

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

let city = City.Melbourne.rawValue

// city is "Melbourne"

Solution 10 - Swift

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

}

if your variable "batteryState" then call:

self.batteryState.description

Solution 11 - Swift

Simple but works...

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

Solution 12 - Swift

Introspection in Swift Enums seems to work partially.

I saw @drewag's response, and found that an Enum with no rawValues can indeed have introspection in Swift 5.X with Xcode 11.5. This code works.

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)

Replace the "\(self)" for "string" in the second Enum and you will get this printout: network 404 string

NOTE: Using String(self) instead of "\(self)" in the first Enumwill require the Enum to conform to theLosslessStringConvertible` protocol, and also add other initializers, so a string interpolation seems to be a good workaround.

To Add a var description: String to the enum, you will have to use a Switch statement will all the enum cases as pointed before

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEvgeniiView Question on Stackoverflow
Solution 1 - SwiftStuartView Answer on Stackoverflow
Solution 2 - SwiftdrewagView Answer on Stackoverflow
Solution 3 - SwiftMatthias VossView Answer on Stackoverflow
Solution 4 - SwiftpkambView Answer on Stackoverflow
Solution 5 - SwiftMarkus RautopuroView Answer on Stackoverflow
Solution 6 - Swiftmz2View Answer on Stackoverflow
Solution 7 - SwiftSevView Answer on Stackoverflow
Solution 8 - SwiftverecView Answer on Stackoverflow
Solution 9 - SwiftNSCoderView Answer on Stackoverflow
Solution 10 - SwiftxevserView Answer on Stackoverflow
Solution 11 - SwiftJimbo JonesView Answer on Stackoverflow
Solution 12 - Swifteharo2View Answer on Stackoverflow