Swift: convertir la valeur d'énumération en chaîne?


141

Compte tenu de l'énumération suivante:

enum Audience {
    case Public
    case Friends
    case Private
}

Comment obtenir la chaîne "Public"de la audienceconstante ci-dessous?

let audience = Audience.Public

2
s'il vous plaît vérifier cette réponse, cela peut vous donner quelques idées sur la façon dont vous pouvez réaliser une telle chose: stackoverflow.com/questions/24648726/enums-with-data-in-swift/…
holex

dans Swift 2 et xcode7, vous n'avez pas besoin de modifier votre code, utilisez simplementprint("\(audience)")
gbdavid

7
Je déteste que l'écoscape Swift soit maintenant rempli de réponses très datées comme celle-ci. Depuis XCode8.2 / Swift3, c'est aussi simple queString(describing: yourEnumValue)
Travis Griggs

@TravisGriggs Cela ne fonctionne plus pour Xcode 11.4
DawnSong

Réponses:


156

Vous ne savez pas dans quelle version Swift cette fonctionnalité a été ajoutée, mais pour le moment ( Swift 2.1 ), vous n'avez besoin que de ce code:

enum Audience : String {
    case public
    case friends
    case private
}

let audience = Audience.public.rawValue // "public"

Lorsque des chaînes sont utilisées pour des valeurs brutes, la valeur implicite de chaque observation est le texte du nom de cette observation .

[...]

enum CompassPoint : String {
    case north, south, east, west
}

Dans l'exemple ci-dessus, CompassPoint.south a une valeur brute implicite de «sud», et ainsi de suite.

Vous accédez à la valeur brute d'un cas d'énumération avec sa propriété rawValue:

let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection is "west"

La source.


8
dans xcode7.3 swift2.2, si je fais des choses comme: print("appState: \(application.applicationState)") j'obtiens appState: UIApplicationState quel est le type et non la représentation sous forme de chaîne réelle de la valeur enum. Est-ce que j'ai râté quelque chose? (PS: pour rawValue j'obtiens juste la valeur Int ...)
Martin

@Cyrus votre scénario est différent de celui qui a été demandé dans ce fil. .rawValuerenverra la valeur brute de votre énumération. Le vôtre est public enum UIApplicationState : Intbien de type Int. Vous n'avez également jamais lu ma réponse qui a une citation de la documentation Apple. ... Si vous souhaitez toujours convertir UIApplicationStateen chaîne, je vous suggère de l'étendre UIApplicationStateavec une propriété calculée personnaliséeextension UIApplicationState { var toString() -> String { /* check self for all diff. cases and return something like "Active" */ }
DevAndArtist

Ne résout pas le problème d'avoir des énumérations de type non String
denis631

1
@ denis631 que voulez-vous dire? Le type brut d'une énumération peut être n'importe quoi. Une énumération peut même être conforme OptionSetsi vous le souhaitez vraiment. Et la question originale concerne de toute façon Strings.
DevAndArtist

1
si mon enum est écrit comme ceci, enum Test: Int {case A, B}, la valeur rawValue retournera bien sûr int, ce que nous recherchons est un moyen d'obtenir le nom du cas sous forme de chaîne. C'est exactement ce qu'a fait @DanilShaykhutdinov. Regardez sa réponse et dans la question d'origine, l'énumération n'a pas de type, pas une chaîne ou un int.
denis631

209

L'interface idiomatique pour «obtenir une chaîne» consiste à utiliser l' CustomStringConvertible interface et à accéder au descriptiongetter. Définissez votre enumcomme:

enum Foo : CustomStringConvertible {
  case Bing
  case Bang
  case Boom
  
  var description : String { 
    switch self {
    // Use Internationalization, as appropriate.
    case .Bing: return "Bing"
    case .Bang: return "Bang"
    case .Boom: return "Boom"
    }
  }
}

En action:

 > let foo = Foo.Bing
foo: Foo = Bing
 > println ("String for 'foo' is \(foo)"
String for 'foo' is Bing

Mise à jour : pour Swift> = 2.0, remplacé PrintableparCustomStringConvertible

Remarque : l'utilisation CustomStringConvertiblepermet Food'adopter un type brut différent. Par exemple, enum Foo : Int, CustomStringConvertible { ... }c'est possible. Cette liberté peut être utile.


2
Un autre moyen plus court de créer la chaîne println est: "String for 'foo' is (foo)"
John MP Knox

3
@ JohnM.P.Knox n'oubliez pas le back-slash comme dans "String for 'foo' is \ (foo)". Edit OK, c'est l'éditeur qui s'en débarrasse, j'ai dû en saisir 2 pour qu'il apparaisse
zmit le

Quel est l'intérêt CustomStringConvertiblesi cela fonctionne aussi bien sans cela?
Daniel van der Merwe

3
CustomStringConvertiblevous permet / vous oblige à définir descriptionce qui vous permet de décider quelle chaîne utiliser pour chaque cas d'énumération - ceci est certainement important pour l'internationalisation et peut-être la lisibilité du code. Si vous ne vous souciez pas de ceux-ci, vous pouvez utiliser 'enum Foo: String {/ * ... * /} `
GoZoner

2
C'est la bonne réponse si votre énumération n'est pas une chaîne ou si vous voulez une chaîne différente de la valeur rawValue. @ denis631
Haagenti

32

Pour l'instant, je redéfinirai l'énumération comme suit:

enum Audience: String {
    case Public = "Public"
    case Friends = "Friends"
    case Private = "Private"
}

pour que je puisse faire:

audience.toRaw() // "Public"

Mais cette nouvelle définition d'énumération n'est-elle pas redondante? Puis-je conserver la définition initiale de l'énumération et faire quelque chose comme:

audience.toString() // "Public"

3
Depuis Xcode 7 Beta 3, vous pouvez simplement écrire votre réponse mais sans le = Stringcar il obtient automatiquement une valeur brute (nom du cas) si vous n'en fournissez pas.
Qbyte

3
Au lieu de .toString (), utilisez maintenant .rawValue
SoftDesigner

Dans Swift 1.2, vous pouvez utiliser: println (Audience.Friends.rawValue)
Oleg Popov


24

J'aime utiliser Printableavec Raw Values.

enum Audience: String, Printable {
    case Public = "Public"
    case Friends = "Friends"
    case Private = "Private"

    var description: String {
        return self.rawValue
    }
}

Ensuite, nous pouvons faire:

let audience = Audience.Public.description // audience = "Public"

ou

println("The value of Public is \(Audience.Public)") 
// Prints "The value of Public is Public"

1
J'aime mieux cette façon que la réponse sélectionnée parce que je peux le faireAudience(rawValue: "Friends")
tidwall

12

Mis à jour pour la sortie de Xcode 7 GM. Cela fonctionne comme on l'espère maintenant - merci Apple!

enum Rank:Int {
    case Ace = 1, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King
}

let r = Rank.Ace

print(r)               // prints "Ace"
print("Rank: \(r)!")   // prints "Rank: Ace!"

2
Dans Swift 2.0, se conformer à CustomStringConvertiblepermettrait en fait de n'utiliser que print(r)dans ce cas.
matm

Dans Xcode 7 beta 4, reflect () semble avoir été désactivé au profit de Mirror (reflétant: x). Cependant, l'objet retourné a une structure différente.
GSnyder

1
Mettez à jour la réponse s'il vous plaît
Ben Sinclair

10

Cela ne pourrait pas être plus simple que cela dans Swift 2 et le dernier Xcode 7 (pas besoin de spécifier le type enum, ou .rawValue, les descripteurs, etc.)

Mis à jour pour Swift 3 et Xcode 8:

    enum Audience {
        case Public
        case Friends
        case Private
    }

    let audience: Audience = .Public  // or, let audience = Audience.Public
    print(audience) // "Public"

Fonctionne parfaitement avec mes
énumérations

Juste une observation: cela fonctionne pour les énumérations auto-créées mais ne fonctionne pas pour quelque chose comme HKWorkoutActivityType
Ace Green

Ainsi que pour les chaînes localisées;)
Eugene Braginets

2
La question originale portait sur la conversion de la valeur enum en chaîne dans vos propres énumérations, c'est pour cela que j'ai donné une réponse ... Si vous aimeriez gérer les énumérations UIKit / AppKit, bien sûr, c'est une autre histoire.
gbdavid

1
@gbdavid - Y a-t-il un Q pour les énumérations UIKit / AppKit? J'ai cherché sur Google et je n'ai pas pu le trouver. Je peux soumettre Q si cela est nécessaire.
benc le

8

Un exemple Swift 3 et supérieur si vous utilisez Ints dans Enum

public enum ECategory : Int{
        case Attraction=0, FP, Food, Restroom, Popcorn, Shop, Service, None;
        var description: String {
            return String(describing: self)
        }
    }

let category = ECategory.Attraction
let categoryName = category.description //string Attraction

Une solution élégante. "\ (category)" ou directement String (décrivant: category) fonctionnerait également. Même pour les énumérations Int.
t1ser

8

Pour toute personne lisant l'exemple du chapitre "A Swift Tour" de "The Swift Programming Language" et cherchant un moyen de simplifier la méthode simpleDescription (), convertir l'énumération elle-même en String en faisant le String(self)fera:

enum Rank: Int
{
    case Ace = 1 //required otherwise Ace will be 0
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King
    func simpleDescription() -> String {
        switch self {
            case .Ace, .Jack, .Queen, .King:
                return String(self).lowercaseString
            default:
                return String(self.rawValue)
        }
     }
 }

2
Assurez-vous simplement que vous n'utilisez pas l'énumération avec "@objc". Cela fait échouer cette approche.
Matt Bearson

5

Après avoir essayé plusieurs façons différentes, j'ai trouvé que si vous ne voulez pas utiliser:

let audience = Audience.Public.toRaw()

Vous pouvez toujours l'archiver en utilisant une structure

struct Audience {
   static let Public  = "Public"
   static let Friends = "Friends"
   static let Private = "Private"
}

puis votre code:

let audience = Audience.Public

fonctionnera comme prévu. Ce n'est pas joli et il y a quelques inconvénients parce que vous n'utilisez pas de "enum", vous ne pouvez pas utiliser le raccourci uniquement en ajoutant .Private ne fonctionnera pas non plus avec les cas de commutation.


Ça a l'air bien. Je me demande quelle serait la meilleure pratique pour ce cas particulier. Je préférerais utiliser la syntaxe struct en raison de la simplicité, mais utiliser struct au lieu de enum ne semble pas correct, ou peut-être que c'est juste moi? Eh bien, rien ne vous empêche de déclarer des variables constantes n'importe où ailleurs, cette fois vous l'ajoutez simplement dans une structure pour qu'elle soit organisée. Pensées?
schystz

Exactement, cela fonctionne comme des variables constantes mais plus organisées. Comme je l'ai déjà dit, le seul problème est le "boîtier de commutation" et les raccourcis ".Private". Si vous construisez à partir de zéro votre application, essayez d'utiliser "enum", n'utilisez les structures que si "enum" ne satisfait pas votre code pour une raison quelconque. J'évite personnellement les variables constantes et j'utilise toujours des structures à la place.
Adriano Spadoni

J'utilise ceci pour les clés par défaut. Plutôt que de me souvenir des clés par défaut dans une application, je vide les clés dans une structure et les extrait à partir de là.
Adrian

3

Il existe plusieurs façons de procéder. Soit vous pouvez définir une fonction dans l'énumération qui renvoie la chaîne en fonction de la valeur du type enum:

enum Audience{
    ...
func toString()->String{
  var a:String

  switch self{
   case .Public:
    a="Public"
   case .Friends:
    a="Friends"
   ...
 }
 return a
}

Ou vous pouvez essayer ceci:

enum Audience:String{
   case Public="Public"
   case Friends="Friends"
   case Private="Private"
}

Et pour l'utiliser:

var a:Audience=Audience.Public
println(a.toRaw())

1

À partir de Swift 3.0, vous pouvez

var str = String(describing: Audience.friends)

1
Incroyable, mais cela fonctionne parfaitement. Approche beaucoup plus courte que «idiomatique». Merci!
Roman
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.