In Swift, is it possible to convert a string to an enum?

SwiftEnums

Swift Problem Overview


If I have an enum with the cases a,b,c,d is it possible for me to cast the string "a" as the enum?

Swift Solutions


Solution 1 - Swift

Sure. Enums can have a raw value. To quote the docs:

> Raw values can be strings, characters, or any of the integer or > floating-point number types > > β€” Excerpt From: Apple Inc. β€œThe Swift Programming Language.” iBooks. https://itun.es/us/jEUH0.l,</cite>

So you can use code like this:

enum StringEnum: String 
{
    case one   = "value one"
    case two   = "value two"
    case three = "value three"
}

let anEnum = StringEnum(rawValue: "value one")!

print("anEnum = \"\(anEnum.rawValue)\"")

Note: You don't need to write = "one" etc. after each case. The default string values are the same as the case names so calling .rawValue will just return a string

EDIT

If you need the string value to contain things like spaces that are not valid as part of a case value then you need to explicitly set the string. So,

enum StringEnum: String 
{
  case one
  case two
  case three
}

let anEnum = StringEnum.one
print("anEnum = \"\(anEnum)\"")

gives

> anEnum = "one"

But if you want case one to display "value one" you will need to provide the string values:

enum StringEnum: String 
{
  case one   = "value one"
  case two   = "value two"
  case three = "value three"
}

Solution 2 - Swift

All you need is:

enum Foo: String {
   case a, b, c, d
}

let a = Foo(rawValue: "a")
assert(a == Foo.a)

let πŸ’© = Foo(rawValue: "πŸ’©")
assert(πŸ’© == nil)

Solution 3 - Swift

In Swift 4.2, the CaseIterable protocol can be used for an enum with rawValues, but the string should match against the enum case labels:

enum MyCode : String, CaseIterable {
    
    case one   = "uno"
    case two   = "dos"
    case three = "tres"
    
    static func withLabel(_ label: String) -> MyCode? {
        return self.allCases.first{ "\($0)" == label }
    }
}

usage:

print(MyCode.withLabel("one")) // Optional(MyCode.one)
print(MyCode(rawValue: "uno"))  // Optional(MyCode.one)

Solution 4 - Swift

In case with an enum with Int type you can do it so:

enum MenuItem: Int {
    case One = 0, Two, Three, Four, Five //... as much as needs

    static func enumFromString(string:String) -> MenuItem? {
        var i = 0
        while let item = MenuItem(rawValue: i) {
            if String(item) == string { return item }
            i += 1
        }
        return nil
    }
}

And use:

let string = "Two"
if let item = MenuItem.enumFromString(string) {
    //in this case item = 1 
    //your code
} 

Solution 5 - Swift

Riffing on djruss70's answer to create highly generalized solution:

extension CaseIterable {
    static func from(string: String) -> Self? {
	    return Self.allCases.first { string == "\($0)" }
    }
    func toString() -> String { "\(self)" }
}

Usage:

enum Chassis: CaseIterable {
    case pieridae, oovidae
}

let chassis: Chassis = Chassis.from(string: "oovidae")!
let string: String = chassis.toString()

Note: this will unfortunately not work if the enum is declared @objc. As far as I know as of Swift 5.3 there is no way to get this to work with @objc enum's except brute force solutions (a switch statement).

If someone happens to know of a way to make this work for @objc enums, I'd be very interested in the answer.

Solution 6 - Swift

Swift 4.2:

public enum PaymentPlatform: String, CaseIterable {
    case visa = "Visa card"
    case masterCard = "Master card"
    case cod = "Cod"

    var nameEnum: String {
        return Mirror(reflecting: self).children.first?.label ?? String(describing: self)
    }

    func byName(name: String) -> PaymentPlatform {
        return PaymentPlatform.allCases.first(where: {$0.nameEnum.elementsEqual(name)}) ?? .cod
    }
}

Solution 7 - Swift

Extending Duncan C's answer

extension StringEnum: StringLiteralConvertible {

    init(stringLiteral value: String){
        self.init(rawValue: value)!
    }

    init(extendedGraphemeClusterLiteral value: String) {
        self.init(stringLiteral: value)
    }

    init(unicodeScalarLiteral value: String) {
        self.init(stringLiteral: value)
    }
}

Solution 8 - Swift

For Int enum and their String representation, I declare enum as follows:

enum OrderState: Int16, CustomStringConvertible {
    
    case waiting = 1
    case inKitchen = 2
    case ready = 3
    
    var description: String {
        switch self {
        case .waiting:
            return "Waiting"
        case .inKitchen:
            return "InKitchen"
        case .ready:
            return "Ready"
        }
    }
    
    static func initialize(stringValue: String)-> OrderState? {
        switch stringValue {
        case OrderState.waiting.description:
            return OrderState.waiting
        case OrderState.inKitchen.description:
            return OrderState.inKitchen
        case OrderState.ready.description:
            return OrderState.ready
     
        default:
            return nil
        }
    }
}

Usage:

order.orderState = OrderState.waiting.rawValue

let orderState = OrderState.init(rawValue: order.orderState)
let orderStateStr = orderState?.description ?? ""
print("orderStateStr = \(orderStateStr)")

Solution 9 - Swift

I used this:

public enum Currency: CaseIterable, Codable {
    case AFN = 971 // Afghani (minor=2)
    case DZD = 012 // Algerian Dinar (minor=2)

...

    private static var cachedLookup: [String: Currency] = [:]
    
    init?(string: String) {
        if Self.cachedLookup.isEmpty {
            Self.cachedLookup = Dictionary(uniqueKeysWithValues: Self.allCases.map { ("\($0)", $0) })
        }
        
        if let currency = Self.cachedLookup[string] {
            self = currency
            return
        } else {
            return nil
        }
    }
}

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
Questionuser2763173View Question on Stackoverflow
Solution 1 - SwiftDuncan CView Answer on Stackoverflow
Solution 2 - SwiftemlaiView Answer on Stackoverflow
Solution 3 - Swiftdjruss70View Answer on Stackoverflow
Solution 4 - SwiftIgorView Answer on Stackoverflow
Solution 5 - SwiftaepryusView Answer on Stackoverflow
Solution 6 - SwiftSBotirovView Answer on Stackoverflow
Solution 7 - SwiftgujciView Answer on Stackoverflow
Solution 8 - SwiftAmmar MujeebView Answer on Stackoverflow
Solution 9 - SwifteostarmanView Answer on Stackoverflow