Pregunta ¿Cómo obtener el nombre del valor de enumeración en Swift?


Si tengo una enumeración con raw Integer valores:

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

let city = City.Melbourne

¿Cómo puedo convertir un city valor a una cadena Melbourne? ¿Este tipo de introspección de nombre de tipo está disponible en el idioma?

Algo como (este código no funcionará):

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

114
2018-06-09 03:04


origen


Respuestas:


A partir de Xcode 7 beta 5 ahora puede imprimir nombres de tipos y casos de enumeración por defecto usando print(_:), o convertir a String utilizando Stringes init(_:) inicialización o sintaxis de interpolación de cadenas. Entonces para tu ejemplo:

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"

Por lo tanto, ya no es necesario definir y mantener una función de conveniencia que active cada caso para devolver un literal de cadena. Además, esto funciona automáticamente para cualquier enumeración, incluso si no se especifica ningún tipo de valor sin formato.

debugPrint(_:) & String(reflecting:) se puede usar para un nombre completamente calificado:

debugPrint(city)
// prints "App.City.Melbourne" (or similar, depending on the full scope)

let cityDebugName = String(reflecting: city)
// cityDebugName contains "App.City.Melbourne"

Tenga en cuenta que puede personalizar lo que se imprime en cada uno de estos escenarios:

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

(No he encontrado una forma de llamar a este valor "predeterminado", por ejemplo, para imprimir "La ciudad es Melbourne" sin recurrir a una declaración de cambio. \(self) en la implementación de description/debugDescription causa una recursión infinita)


Los comentarios anteriores Stringes init(_:) & init(reflecting:) los inicializadores describen exactamente lo que se imprime, dependiendo de a qué se ajuste el tipo reflejado:

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


Ver el Notas de lanzamiento para obtener información sobre este cambio.


91
2017-08-08 14:13



No hay introspección en los casos enum en este momento. Deberá declararlos de forma manual:

enum City : String, Printable {
  case Melbourne = "Melbourne"
  case Chelyabinsk = "Chelyabinsk"
  case Bursa = "Bursa"

  var description : String {
    get {
        return self.rawValue
    }
  }
}

Nota: Los Printable el protocolo actualmente no funciona en Playgrounds. Si quieres ver la cuerda en un patio de recreo, deberás llamar aRaw () manualmente

Si necesita que el tipo sin procesar sea un Int, tendrá que hacer un cambio usted mismo:

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

  var description : String {
    get {
      switch(self) {
        case Melbourne:
          return "Melbourne"
        case Chelyabinsk:
          return "Chelyabinsk"
        case Bursa:
          return "Bursa"
      }
    }
  }
}

66
2018-06-09 03:08



En Swift-3 (probado con XCode 8.1) puede agregar los siguientes métodos en su enumeración:

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

Luego puede usarlo como una llamada a método normal en su instancia enum. También podría funcionar en versiones anteriores de Swift, pero no lo he probado.

En tu ejemplo:

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"

Si desea proporcionar esta funcionalidad a todas sus enumeraciones, puede hacer que sea una extensión:

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

Esto solo funciona para enums de Swift.


19
2017-11-16 15:22



Para Objective-C enums la única manera actualmente parece ser, por ejemplo, extender la enumeración con CustomStringConvertible terminando con algo como:

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

Y luego lanzar el enum como String:

String(UIDevice.currentDevice().batteryState)

12
2018-03-02 14:15



Esto es tan decepcionante

Para el caso en que necesita esos nombres (que el compilador conoce perfectamente la ortografía exacta de, pero se niega a permitir el acceso, ¡gracias Swift team!), Pero no quiere o no puede hacer que String sea la base de su enumeración, una La alternativa detallada y engorrosa es la siguiente:

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

Puede usar lo anterior de la siguiente manera:

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

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

Y obtendrá el resultado esperado (el código de la Columna es similar, pero no se muestra)

fetching element Title, column: Collections, row: 0

En lo anterior, hice el description propiedad se refieren a la string método, pero esto es una cuestión de gusto. También tenga en cuenta que llamado static las variables deben ser de alcance calificado por el nombre de su tipo adjunto, ya que el compilador es demasiado amnésico y no puede recordar el contexto por sí mismo ...

El equipo de Swift debe ser realmente comandado. Crearon enum que no puedes enumerate y eso que puedes usar enumerate son "Secuencias" pero no enum!


6
2017-12-24 13:51



Además del soporte de String (...) (CustomStringConvertible) para las enumeraciones en Swift 2.2, también hay un soporte de reflexión algo roto para ellos. Para los casos enum con valores asociados, es posible obtener la etiqueta del caso enum utilizando la reflexión:

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"

Al romperse, sin embargo, quería decir que para enumeraciones "simples", la reflexión anterior se basa label propiedad calculada simplemente devuelve nil (boo-hoo).

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

La situación con la reflexión debería mejorar después de Swift 3, al parecer. La solución por ahora es String(…), como se sugiere en una de las otras respuestas:

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

5
2018-04-28 23:36



Simple pero funciona ...

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
2018-04-09 11:04



Swift ahora tiene lo que se conoce como Valor bruto implícitamente asignado. Básicamente, si no le da valores brutos a cada caso y la enumeración es de tipo String, deduce que el valor en bruto del caso es él mismo en formato de cadena. Vamos, dale una oportunidad.

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

let city = City.Melbourne.rawValue

// city is "Melbourne"

1
2018-03-02 14:41