Swift: преобразовать значение перечисления в строку?

141

Учитывая следующее перечисление:

enum Audience {
    case Public
    case Friends
    case Private
}

Как мне получить строку "Public"из audienceконстанты ниже?

let audience = Audience.Public
ma11hew28
источник
2
пожалуйста, проверьте этот ответ, он может дать вам некоторые идеи о том, как вы можете достичь такой цели: stackoverflow.com/questions/24648726/enums-with-data-in-swift/…
holex
в Swift 2 и xcode7 вам не нужно ничего менять в своем коде, просто используйтеprint("\(audience)")
gbdavid
7
Я ненавижу то, что экосапорт Свифта теперь заполнен очень устаревшими ответами, подобными этому. Что касается XCode8.2 / Swift3, это так же просто, какString(describing: yourEnumValue)
Трэвис Григгс
@TravisGriggs Это больше не работает для Xcode 11.4
DawnSong

Ответы:

156

Не уверен, в какой версии Swift эта функция была добавлена, но сейчас ( Swift 2.1 ) вам нужен только этот код:

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

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

Когда строки используются для необработанных значений, неявное значение для каждого случая - это текст имени этого случая .

[...]

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

В приведенном выше примере CompassPoint.south имеет неявное необработанное значение «south» и т. Д.

Вы получаете доступ к необработанному значению регистра перечисления с помощью его свойства rawValue:

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

Источник.

DevAndArtist
источник
8
в xcode7.3 swift2.2, если я делаю что-то вроде: print("appState: \(application.applicationState)") я получаю, appState: UIApplicationState который является типом, а не фактическим строковым представлением значения перечисления. Я что-то здесь упускаю? (PS: для rawValue я просто получаю значение Int ...)
Martin
@Cyrus ваш сценарий отличается от того, который был задан в этой теме. .rawValueвернет необработанное значение вашего перечисления. Ваш, public enum UIApplicationState : Intкоторый действительно имеет тип Int. Вы также никогда не читали мой ответ, в котором есть цитата из документов Apple. ... Если вы все еще хотите преобразовать UIApplicationStateв строку, я бы посоветовал вам расширить ее UIApplicationStateс помощью пользовательского вычисляемого свойстваextension UIApplicationState { var toString() -> String { /* check self for all diff. cases and return something like "Active" */ }
DevAndArtist
Не решает проблему с наличием перечислений не
строкового
1
@ denis631 что ты имеешь ввиду? Необработанный тип перечисления может быть любым. Перечисление может даже соответствовать, OptionSetесли вы действительно хотите. И оригинальный вопрос в любом случае о струнах.
DevAndArtist
1
если мой enum написан так, enum Test: Int {case A, B}, rawValue, конечно, вернет int обратно, и мы ищем способ получить имя case в виде String. Именно это и сделал @DanilShaykhutdinov. Посмотрите на его ответ, и в исходном вопросе enum не имеет типа, ни String, ни Int.
denis631
209

Идиоматический интерфейс для получения строки - это использование CustomStringConvertible интерфейса и доступ к descriptionполучателю. Определите ваш enumкак:

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

В действии:

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

Обновлено : для Swift> = 2.0 заменено PrintableнаCustomStringConvertible

Примечание . Использование CustomStringConvertibleпозволяет Fooиспользовать другой необработанный тип. Например enum Foo : Int, CustomStringConvertible { ... }возможно. Эта свобода может быть полезной.

GoZoner
источник
2
Другой более короткий способ создать строку println: «Строка для 'foo' is (foo)"
Джон Нокс,
3
@ JohnM.P.Knox не забывайте обратную косую черту, как в "Строка для 'foo' is \ (foo)". Edit OK, это редактор, избавляющийся от него, мне пришлось ввести 2 из них, чтобы он появился
zmit
Какой смысл, CustomStringConvertibleесли это работает так же хорошо без него?
Даниэль ван дер Мерве
3
CustomStringConvertibleпозволяет / требует от вас определить, descriptionчто позволяет вам решить, какую строку использовать для каждого случая перечисления - это, безусловно, важно для интернационализации и, возможно, читабельности кода. Если вас это не волнует, вы можете использовать 'enum Foo: String {/ * ... * /} `
GoZoner
2
Это правильный ответ, если ваше перечисление не является String или вы хотите другую строку, чем rawValue. @ denis631
Haagenti
32

Сейчас я переопределю перечисление как:

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

так что я могу сделать:

audience.toRaw() // "Public"

Но не является ли это новое определение перечисления избыточным? Могу ли я сохранить первоначальное определение enum и сделать что-то вроде:

audience.toString() // "Public"
ma11hew28
источник
3
Начиная с Xcode 7 Beta 3, вы можете просто написать свой ответ, но без такового, = Stringпотому что он автоматически получает необработанное значение (название дела), если вы его не предоставите.
Qbyte
3
Вместо .toString () теперь используйте .rawValue
SoftDesigner
В Swift 1.2 вы можете использовать: println (Audience.Friends.rawValue)
Олег Попов
32

В Swift 3 вы можете использовать это

var enumValue = Customer.Physics
var str = String(describing: enumValue)

от Swift как использовать enum для получения строкового значения

Данил Шайхутдинов
источник
2
Это действительно полезно, особенно если мой enumне основан на Strings
daspianist
1
"\(enumValue)"Делает то же самое. ^^
эонист
Это лучший ответ. Не требует создания типа enum String.
scord
24

Мне нравится использовать Printableс Raw Values.

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

    var description: String {
        return self.rawValue
    }
}

Тогда мы можем сделать:

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

или

println("The value of Public is \(Audience.Public)") 
// Prints "The value of Public is Public"
Simple99
источник
1
Мне нравится этот способ лучше, чем выбранный ответ, потому что я могу сделатьAudience(rawValue: "Friends")
tidwall
12

Обновлено для выпуска Xcode 7 GM. Это работает, как можно было бы надеяться сейчас - спасибо 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
В Swift 2.0 соответствие CustomStringConvertibleфактически позволит использовать только print(r)в этом случае.
Мат
В Xcode 7 beta 4, отражение (), кажется, было отключено в пользу зеркала (отражает: x). Однако возвращаемый объект имеет другую структуру.
GSnyder
1
Обновите ответ, пожалуйста
Бен Синклер,
10

Это не может быть проще, чем это в Swift 2 и последней версии Xcode 7 (не нужно указывать тип enum или .rawValue, дескрипторы и т. Д.)

Обновлено для Swift 3 и Xcode 8:

    enum Audience {
        case Public
        case Friends
        case Private
    }

    let audience: Audience = .Public  // or, let audience = Audience.Public
    print(audience) // "Public"
gbdavid
источник
Отлично работал с моими перечислениями, поддерживаемыми Int
chrislarson
Просто наблюдение: это работает для самостоятельно созданных перечислений, но не работает для чего-то вроде HKWorkoutActivityType
Ace Green
Как и для локализованных струн;)
Евгений Брагинец
2
Первоначальный вопрос был о преобразовании значения enum в строку в ваших собственных перечислениях, поэтому я дал ответ на этот вопрос ... Если вы хотите работать с перечислениями UIKit / AppKit, конечно, это другая история.
gbdavid
1
@gbdavid - есть ли Q для перечислений UIKit / AppKit? Я погуглил и не смог найти. Я могу представить Q, если это необходимо.
Бен
8

Быстрый пример 3 и выше при использовании Ints в 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
Цукими
источник
Элегантное решение. «\ (категория)» или непосредственно строка (описывающая категорию) также будет работать. Даже для Int en.
t1ser
8

Для любого, кто читает пример в главе «Swift Tour» «The Swift Programming Language» и ищет способ упростить метод simpleDescription (), преобразование самого enum в String, сделав String(self)это, сделает это:

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
Просто убедитесь, что вы не используете enum с "@objc". Это приводит к провалу такого подхода.
Мэтт Берсон
5

Попробовав несколько разных способов, я обнаружил, что если вы не хотите использовать:

let audience = Audience.Public.toRaw()

Вы все еще можете заархивировать его, используя структуру

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

тогда ваш код:

let audience = Audience.Public

будет работать как положено. Это не красиво, и есть некоторые недостатки, потому что вы не используете "enum", вы не можете использовать ярлык, только добавляя .Private ни один не будет работать с переключателями.

Адриано Спадони
источник
Выглядит аккуратно Интересно, что будет лучшей практикой для этого конкретного случая. Я бы предпочел использовать синтаксис struct из-за простоты, но использование struct вместо enum кажется неправильным, или, может быть, это только я? Что ж, ничто не мешает вам просто объявить постоянные переменные где-либо еще, на этот раз вы просто добавляете их в структуру, чтобы она была организована. Мысли?
Schystz
Точно, это работает как постоянные переменные, но более организованно. Как я уже говорил, единственной проблемой является «случай переключения» и ярлыки «.Private». Если вы создаете приложение с нуля, попробуйте использовать «enum», используйте структуры, только если «enum» по какой-то причине не удовлетворяет ваш код. Я лично избегаю использования константных переменных и всегда использую структуры.
Адриано Спадони
Я использую это для ключей по умолчанию. Вместо того, чтобы помнить ключи по умолчанию в приложении, я выкидываю ключи в структуру и извлекаю их оттуда.
Адриан
3

Есть несколько способов сделать это. Либо вы можете определить функцию в перечислении, которая возвращает строку на основе значения типа перечисления:

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

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

Или вы можете попробовать это:

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

И использовать это:

var a:Audience=Audience.Public
println(a.toRaw())
Друв Рамани
источник
1

Начиная с Swift 3.0 вы можете

var str = String(describing: Audience.friends)
iosMentalist
источник
1
Невероятно, но это прекрасно работает. Гораздо короче, чем «идиоматический» подход. Спасибо!
Роман