Can you initialize an Enum value from the name of its case (*not* its RawValue?)

self init isn t called on all paths before returning from initializer enum
init swift enum
swift enum default

Consider this enumeration (note its type is Int)

enum MyTestEnum : Int{
    case one     = 1
    case eight   = 8
    case unknown = -1
}

You can easily initialize a version of this based on the raw value, like so...

let value = MyTestEnum(rawValue:-1)

I'm trying to find out if it can be initialized with a string representation of the case name itself (again, not the raw value, but the word after 'case') like so...

let value = MyTestEnum(caseName:"eight")

Note: I want this to work with any enum if possible, regardless of its raw value type. For instance, this one...

enum MyOtherEnum{
    case xxx
    case yyy
    case zzz
}

let value = MyOtherEnum(caseName:"xxx")

So can this be done?

Thoughts:

  • I think Swift has a way to instantiate a class given a string representing the fully-qualified class-name. Perhaps something similar can be used here.

In Swift 4.2, this is quite easy to do now using CaseIterable.

enum MyOtherEnum: CaseIterable {
    case xxx
    case yyy
    case zzz

    init?(caseName: String) {
        for value in MyOtherEnum.allCases where "\(value)" == caseName {
            self = value
            return
        }

        return nil
    }
}

enum MyTestEnum: Int, CaseIterable{
    case one     = 1
    case eight   = 8
    case unknown = -1

    init?(caseName: String) {
        for value in MyTestEnum.allCases where "\(value)" == caseName {
            self = value
            return
        }

        return nil
    }
}

What I am doing here is creating a failable initializer, which will then iterate through all potential cases, testing to see if the "\value" for each case matches the caseName passed in at initialization.

When a match is found, self is set and the loop ends. Otherwise, nil is returned for the call.

Below, are two working and two failing examples:

let myOtherEnum = MyOtherEnum(caseName:"xxx")
print(myOtherEnum) // MyOtherEnum.xxx

let myTestEnum = MyTestEnum(caseName:"eight")
print(myTestEnum?.rawValue) // 8

let myOtherEnumFail = MyOtherEnum(caseName:"aaa")
print(myOtherEnumFail) // nil

let myTestEnumFail = MyTestEnum(caseName:"ten")
print(myTestEnumFail) // nil

IOS 9 Programming Fundamentals with Swift: Swift, Xcode, and Cocoa , This difference makes sense, because adoption of a protocol does not (and must not) time I initialized one of these enums from its raw value, so I gave each enum a name, that calls the built-in init(rawValue:) initializer: enum Fill : Int { case  Enumeration (enum) in Java is a datatype which stores a set of constant values. You can use enumerations to store fixed values such as days in a week, months in a year etc. You can define an enumeration using the keyword enum followed by the name of the enumeration as − enum Days { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY }

You can go with custom initializer

extension MyTestEnum {
    public static func allValues() -> [MyTestEnum] {
        let retVal = AnySequence { () -> AnyIterator<MyTestEnum> in
            var raw = 0
            return AnyIterator {
                let current = withUnsafePointer(to: &raw) {
                    $0.withMemoryRebound(to: MyTestEnum.self, capacity: 1) { $0.pointee }
                }
                guard current.hashValue == raw else { return nil }
                raw += 1
                return current
            }
        }

        return [MyTestEnum](retVal)
    }

    init?(caseName: String){
        for v in MyTestEnum.allValues() {
            if "\(v)" == caseName {
                self = v
                return
            }
        }
        self = MyTestEnum.unknown
    }
}

let test = MyTestEnum(caseName: "eight")

or simple manually all your case :)

extension MyTestEnum {
 init?(caseName: String){
   switch caseName {
     case "eight": self.init(rawValue: 8)
     case "one": self.init(rawValue: 1)
     default: self.init(rawValue: -1)
   }
 }
}

let test1 = MyTestEnum(caseName: "eight") 
let test2 = MyTestEnum(rawValue: 1)

Hope this helps !!

iOS 13 Programming Fundamentals with Swift: Swift, Xcode, and , You could implement a multistate value yourself; if there are five possible those numeric values correctly and making sure that no other values are used. A with an enum, the name of the enum and the names of its cases tell you its Moreover, you can store extra information in an enum's associated value or raw value. Mathematically speaking, the mapping from a type to its raw value must be injective. It must always be possible to reconstruct the original value only from a given raw value. Unfortunately, as soon

It sounds like your want your enum cases to have raw Int values and raw String values. It's not strictly possible to do this, but perhaps this comes close:

enum MyTestEnum : String {
    case one
    case eight
    case unknown

    var intValue: Int {
        switch self {
        case one: return 1
        case eight: return 8
        case unknown: return -1
        }
    }
}

Now you can initialize from case names, but you can also retrieve an intValue when needed. (If needed, you could easily add a failable initializer to allow initialization from integers as well.)

Enumerations, If a value (known as a raw value) is provided for each enumeration case, the value can You introduce enumerations with the enum keyword and place their entire Like other types in Swift, their names (such as CompassPoint and Planet ) is inferred when it's initialized with one of the possible values of CompassPoint . Java provides a valueOf(String) method for all enum types. Thus, we can always get an enum value based on the declared name: assertSame(Element.LI, Element.valueOf("LI")); However, we may want to look up an enum value by our label field as well. To do that we can add a static method:

Why Swift Enums with Associated Values Cannot Have a Raw Value, Swift enums still have that core functionality but you can do a lot more type you choose, the value you assign to a case is called a rawValue . You can only use typeId (AX 2009 and before) or extendedTypeStr (AX 2012) on extended data types (EDT), not enums like NoYes. It can be used on NoYesId, as it is an EDT. dialog.addFieldValue(typeid(NoYesId), NoYes::Yes, "Check"); You must call run before you can meaningful acquire the value. Dialog dialog =

Swift enums: Basics - Cosmin Mircea, That will save you a bit of time when defining an enum. to initialize an enum's case through it's rawValue by using the enum's type by using the enum's name and through dot syntax call one of its cases (=Days.sunday). Second, you can assign a raw value to the first case and let Swift assign the rest:. Animal_Zebra // assigned value is 6} ; Examples of enum in C++. It’s time to discuss enum methods in C++ with explained examples: 1. Unscoped Enumeration Method. enum enum-name { enumerator = value, enumerator = value, ..} In the above-unscoped enumeration, the underlying type is not fixed.

Enum Raw Values and Failable Initializers, If you assign raw values to a Swift enum the compiler will even generate a failable initializer for you. It is then not uncommon to see a method in the view controller with a big switch to Each case of a Swift enum can be assigned a raw value. If you use a String the default value is simply the case name:. Beginning with C# 7.3, you can use System.Enum in a base class constraint (that is known as the enum constraint) to specify that a type parameter is an enumeration type. Conversions For any enumeration type, there exist explicit conversions between the enumeration type and its underlying integral type.

Comments
  • Is this for the purpose of JSON (de)seriailzation?
  • No, it's for general-purpose (we do it in other languages without issue) but the particular use-case that has me trying this is writing an Xcode extension and using an enumeration's case names to be the command IDs, and the string rawValue to be the label. When we get the command back from the user, we get the command ID so I'm trying to re-create the case so I can use it in a switch.
  • Is there any reason you're not using a String rawValue? Do you need the 8, 2, -1,... ?
  • As mentioned above, there may not be any raw value, let alone a string. Look at MyOtherEnum above. It doesn't have a string raw value, but it does have the case names 'xxx', 'yyy' and 'zzz'.
  • I would just use self = .eight, self = .one, etc. The connection to raw values gets confusing (for enums whose cases aren't literally named after their raw values)
  • This doesn't really solve our problem. The problem isn't just initializing from a string, it's initializing from an existing name. With this, we would have to maintain the list inside the init statement. (As a side note, you don't need the init calls with raw values as you could just specify the value directly since you're already doing it manually.)
  • @Alexander wow, really??? i can't use self = .eight in init method, i use swift 4, what version of swift are you using?
  • @SuaLe swift.sandbox.bluemix.net/#/repl/5a31e561e1498b18dac8b1d8
  • Not quite. I think I confused things by mentioning raw values. Just forget them altogether. Again, I'm trying to create an instance of MyTestEnum.eight from the string "eight" since that's the name of the case. Make sense?
  • Yes, this solution does that--if you need no integer raw values, then just leave off the intValue computed property. Simply having a raw value of String will automatically allow you to initialize your cases by name.
  • (If your question, however, is "can I initialize enums by name without giving them a raw value of String?" then the answer is "Nope. Not unless you want to write the initializer yourself.")
  • Your statement "imply having a raw value of String will automatically allow you to initialize your cases by name" is not really true. It initializes by it's raw value. It's just if you don't explicitly give it one, it uses the case name, but if you do (and in our case a lot of times we do) you can't use that approach. That's actually what we're trying to get around.
  • What about reflection, or type-instance-creation from a string representation? You can do it with other classes. Perhaps you can also do it for enums.