How to handle decoding of two possible types for one key in Swift?

I have a Codable struct that is used to decode incoming JSON. Unfortunately, sometimes one of its key values ​​is a string, and sometimes a float. I was able to sing a couple of do / try / catch blocks below to make it work, but is there a better way to handle this?

struct Project: Codable {
    public let version: Float

    init(from decoder: Decoder) throws {
        var decodedVersion: Float = 1.0
        do {
            decodedVersion = try values.decode(Float.self, forKey: .version)
        } catch {
            do {
                if let inVersion = try Float(values.decode(String.self, forKey: .version)) {
                    decodedVersion = inVersion
                }
            } catch {
                throw error
            }
        }
        version = decodedVersion
    }
}
+5
source share
1 answer

If in your JSON the value associated with the key can be sometimes Floatand sometimes String(in addition to fixing this error in the 😉 backend), you can follow this approach.

Let's say this is your "funny" JSON

let data = """
[
{
    "magicField": "one"
},
{
    "magicField":1
}
]
""".data(using: .utf8)!

Well, how can we elegantly present this type of data in Swift?

struct Element:Decodable {
    let magicField: ???
}

, magicField , Float String.

... Enum 😅

enum QuantumValue: Decodable {

    case float(Float), string(String)

    init(from decoder: Decoder) throws {
        if let float = try? decoder.singleValueContainer().decode(Float.self) {
            self = .float(float)
            return
        }

        if let string = try? decoder.singleValueContainer().decode(String.self) {
            self = .string(string)
            return
        }

        throw QuantumError.missingValue
    }

    enum QuantumError:Error {
        case missingValue
    }
}

, QuantumValue Float String. 1 1 .

JSON

struct Element:Decodable {
    let magicField: QuantumValue
}

. JSON.

if let elms = try? JSONDecoder().decode([Element].self, from: data) {
    print(elms)
}

[
Element(magicField: QuantumValue.string("one")),
Element(magicField: QuantumValue.float(1.0))
]

( )

switch magicField {
    case .string(let text):
        println(text)
    case .float(let num):
        println(num)
}
+26

Source: https://habr.com/ru/post/1689341/


All Articles