Search code examples
swiftcodable

How do you get the raw value from a Decodable enum?


I'm decoding JSON, and one of my values can either be an Int or a String. I found this code online (and edited it) for how to make it so it can be either an int or a string:

enum StrOrInt: Decodable {
    
    case int(Int), string(String)
    
    init(from decoder: Decoder) throws {
        if let int = try? decoder.singleValueContainer().decode(Int.self) {
            self = .int(int)
            return
        }
        
        if let string = try? decoder.singleValueContainer().decode(String.self) {
            self = .string(string)
            return
        }
        
        throw sot.missingValue
    }
    
    enum sot: Error {
        case missingValue
    }
}

This code works, but say it was decoding a string "test string". I would expect the results to be "test string", but instead the results are string("test string").

Is there a way to fix this?


Solution

  • First of all, your title is wrong. There are no "raw values" in this story. And that actually makes sense, since you can't set a raw value as if it were a variable. What you've found is an enum that has cases with associated values.

    Second, your expectations are wrong. If we decode a string into your enum, what you have is still not a string; it's an enum with a string associated value.

    So maybe the problem is merely that you don't understand how to extract the string or the int, i.e. how to pull out an associated value. The answer is: use an if case let statement.

    So, if you've decoded into your enum and it is called si:

        if case StrOrInt.string( let s ) = si {
            // if we get here, `si` was holding a string
            // and `s` is now that string
            print(s)
        }
    

    That will print the value held by the .string case, if this is the string case.

    [By the way: this is almost exactly how Optionals work. Optional("hello") is actually an enum case with an associated value, Optional.some("hello"). Just thought you'd like to know.]