如何处理Swift中一个键的两种可能类型的解码?

raw*_*bee 5 swift codable

我有一个Codable结构,用于解码传入的JSON.不幸的是,有时它的一个键的值是一个字符串,有时它是一个浮点数.我能够在下面拼凑一些do/try/catch块以使其工作,但是有更好的方法来处理它吗?

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
    }
}
Run Code Online (Sandbox Code Playgroud)

Luc*_*tti 28

如果在您的JSON中,与键相关联的值有时可能是a Float,有时是String(除了在后端修复此错误),您可以遵循此方法.

让我们说这是你的"搞笑"JSON

let data = """
[
{
    "magicField": "one"
},
{
    "magicField":1
}
]
""".data(using: .utf8)!
Run Code Online (Sandbox Code Playgroud)

好的,我们如何在Swift中优雅地表示这种数据?

struct Element:Decodable {
    let magicField: ???
}
Run Code Online (Sandbox Code Playgroud)

我们希望magicField始终拥有一个价值,有时是一个Float,有时一个String.

我们可以用Quantum Mechanics ...或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
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,type的值QuantumValue可以包含a Float或a String.始终为1且正好为1.

元件

我们现在可以定义JSON的一般元素

struct Element:Decodable {
    let magicField: QuantumValue
}
Run Code Online (Sandbox Code Playgroud)

解码

而已.让我们最终解码JSON.

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

结果

[
Element(magicField: QuantumValue.string("one")),
Element(magicField: QuantumValue.float(1.0))
]
Run Code Online (Sandbox Code Playgroud)