How to get the name of enumeration value in Swift?

前端 未结 12 1371
太阳男子
太阳男子 2020-11-29 23:53

If I have an enumeration with raw Integer values:

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

let city = City.Melbourne
         


        
相关标签:
12条回答
  • 2020-11-30 00:32

    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
    
    0 讨论(0)
  • 2020-11-30 00:33

    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.

    0 讨论(0)
  • 2020-11-30 00:35

    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
    
    0 讨论(0)
  • 2020-11-30 00:37

    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:

    https://forums.swift.org/t/why-is-an-enum-returning-enumname-rather-than-caselabel-for-string-describing/27327

    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.

    0 讨论(0)
  • 2020-11-30 00:42

    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"
    
    0 讨论(0)
  • 2020-11-30 00:43

    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"
        }
    }
    
    0 讨论(0)
提交回复
热议问题