Home > database >  Swift equivalent of Java Enum.valueOf
Swift equivalent of Java Enum.valueOf

Time:09-16

I found two answered questions about how to get an enum constant's name as a String. I want to do the vice-versa, i.e. getting the enum constant with a given name in a String:

enum Unit: Int {
    case SECOND
    case MINUTE
    case HOUR
    
    static func valueOf(unit: String) -> Unit {
        // ?
    }
} 

I want to keep the rawValue to be an Int.

Update: To make the intention clear, I want to persist an object that has a Unit property. I also want to display the unit chosen by the user in the UI, as a localized string. Therefore I need to assign a constant and unique value, the integer, and a String to each enum value.

CodePudding user response:

There is no easy built-in conversion. You can make the enum iterable and iterate over the strings util you find the correct one:

enum Unit: Int, CaseIterable {
    case SECOND
    case MINUTE
    case HOUR

    static func valueOf(unit: String) -> Unit? {
        for x in Unit.allCases {
            if String(describing: x)==unit {
                return x
            }
        }
        return nil
    }
}

You'd need to deal the the possibility that an input string might not mach any valid case-string. I used an optional, but you could as well throw an exception.

Several remarks:

  • This code is case sensitive. So "HOUR" will not lead to the same result as "hour". If needed, add a case normalisation.
  • This code is not optimal, since it will perform a lot of string conversions every iteration on every call. A better alternative would be to initialise a dictionary once, and use it subsequently

The latter could look like:

private static var ready = false
private static var strings = [String : Unit] ()
static func valueOf2(unit: String) -> Unit? {
    if !ready {
        for x in Unit.allCases {
            strings [String(describing: x)]=x
        }
        ready = true
    }
    return strings[unit]
}

CodePudding user response:

Swift has a CaseIterable protocol that you can use to find the case from its raw value.

enum Unit: Int, CaseIterable {
    case second = 100
    case minute = 200
    case hour = 300

    static func caseFrom(rawValue: Int) -> Unit? {
        return allCases.first { $0.rawValue == rawValue }
    }
}

if let unitCase = Unit.caseFrom(rawValue: 200) {
    print(unitCase)
}

The premise of this enum is a bit confusing to me but this is what you're looking for.

  • Related