【问题标题】:How to use enum with assotiated values together with codable protocol?如何将带有关联值的枚举与可编码协议一起使用?
【发布时间】:2021-07-24 10:40:59
【问题描述】:

我会解码以下 JSON,但它失败了。

{
    "keyPath": [
        "791186780675587"
    ],
    "value": {
        "name": "fff"
    },
    "operation": "setValue"
}

解码器也应该能够解码以下内容:

{
    "keyPath": [
        "791186780675587"
    ],
    "value": "some_string",
    "operation": "setValue"
}

区别在于value 字段。

根元素的类型为UpdateIn

struct UpdateIn: Content {
    var keyPath: [String]
    var value: Value
    var operation: String
}

value里面声明为enum

但是enum 是如何声明的,但我不明白是什么。

enum Value: Codable {
    case str(String)
    case formField(FormField)
    case passType(PassType)
    case event(Event)
    private enum CodingKeys: String, CodingKey {
        case str, formField, passType, event
    }
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        switch self {
        case let .str(string):
            try container.encode(string, forKey: .str)
        case let .formField(field):
            try container.encode(field, forKey: .formField)
        case let .passType(field):
            try container.encode(field, forKey: .passType)
        case let .event(field):
            try container.encode(field, forKey: .event)
        }
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        switch container.allKeys.first {
        case .str:
            self = try .str(container.decode(String.self, forKey: .str))
        case .formField:
            self = try .formField(container.decode(FormField.self, forKey: .formField))
        case .passType:
            self = try .passType(container.decode(PassType.self, forKey: .passType))
        case .event:
            self = try .event(container.decode(Event.self, forKey: .event))
        default:
            throw DecodingError.dataCorrupted(
                .init(
                    codingPath: container.codingPath,
                    debugDescription: "invalid data"
                )
            )
        }
    }
}

基本上value 字段可以是 4 种不同的类型,简单字符串或事件,或其他两种。 (PassType, FormField)

case str(String)
case formField(FormField)
case passType(PassType)
case event(Event)

运行解码会引发这个错误:

键值的无效数据

因为在switchdefault 的情况下被调用,因为container.allKeys 有0 项,所以switch container.allKeys.first 将跳转到default

那么Value 声明有什么问题?

啊,是的,这就是Event struct 的样子:

struct Event: Content {
    var name: String
}

【问题讨论】:

  • 嘿,你得到答案了吗?
  • 是的,非常感谢,它有效

标签: json swift enums codable


【解决方案1】:

关键是Value 需要自定义解码器,UpdateIn 需要不需要

假设Eventdecodable。您首先尝试解码为第一种类型(在您的情况下为字符串),然后移动到下一个和下一个。

enum Value {
    case string(String)
    case event(Event)
}

extension Value: Decodable {
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let string = try? container.decode(String.self) {
            self = .string(string)
        } else {
            try self = .event(container.decode(Event.self))
        }
    }
}

完整样本

let j1 = """
{
    "keyPath": [
        "791186780675587"
    ],
    "value": {
        "name": "fff"
    },
    "operation": "setValue"
}
""".data(using: .utf8)!

let j2 = """

{
    "keyPath": [
        "791186780675587"
    ],
    "value": "simpleStrig",
    "operation": "setValue"
}
""".data(using: .utf8)!

struct UpdateIn: Decodable {
    var keyPath: [String]
    var value: Value
    var operation: String
}

enum Value {
    case string(String)
    case event(Event)
}

struct Event: Codable {
    var name: String
}

extension Value: Decodable {
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let string = try? container.decode(String.self) {
            self = .string(string)
        } else {
            try self = .event(container.decode(Event.self))
        }
    }
}

let decoder = JSONDecoder()
print(try! decoder.decode(UpdateIn.self, from: j1).value)
print(try! decoder.decode(UpdateIn.self, from: j2).value)

【讨论】:

    猜你喜欢
    • 2019-08-05
    • 2013-01-15
    • 1970-01-01
    • 2018-05-14
    • 2016-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多