将未知的 Encodable 枚举值解码为默认值

xxt*_*axx 5 enums json deserialization swift codable

我必须像这样反序列化一个 JSON 字符串:

{ "name" : "John Smith", "value" : "someValue" }
Run Code Online (Sandbox Code Playgroud)

在 Swift 4 中,“value”应该是一个枚举,整个对象是一个结构体,如下所示:

struct MyType {
    name: String?
    value: Value?
}
Run Code Online (Sandbox Code Playgroud)

在未来的某个时候,后端可能会添加新的枚举值,所以我认为进行一些回退是明智的。

我以为我可以创建一个枚举

enum Value {
    case someValue
    case someOtherValue
    case unknown(value: String)
}
Run Code Online (Sandbox Code Playgroud)

但我无法解决如何反序列化该枚举并使其工作。以前我只是使用String枚举,但反序列化未知值会引发错误。

是否有一种简单的方法可以使其工作,或者我应该将值反序列化为 aString并在结构中创建一个自定义 getter 并使用 switch 语句返回其中一种情况(甚至可能不是在结构本身中,而是在我的视图模型中)?

PGD*_*Dev 4

您可以显式地实现init(from decoder: Decoder)encode(to encoder: Encoder)处理每种情况,即

struct MyType: Codable {
    var name: String?
    var value: Value?

    enum CodingKeys: String, CodingKey {
        case name
        case value
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decode(String.self, forKey: .name)
        let strValue = try values.decode(String.self, forKey: .value)
        //You need to handle every case explicitly
        switch strValue {
        case "someValue":
            value = Value.someValue
        case "someOtherValue":
            value = Value.someOtherValue
        default:
            value = Value.unknown(value: strValue)
        }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
        if let val = value {
            //You need to handle every case explicitly
            switch val {
            case .someValue, .someOtherValue:
                try container.encode(String(describing: val), forKey: .value)
            case .unknown(let strValue):
                try container.encode(strValue, forKey: .value)
            }
        }
    }
}

enum Value {
    case someValue
    case someOtherValue
    case unknown(value: String)
}
Run Code Online (Sandbox Code Playgroud)