【问题标题】:Decoding unknown Encodable enum values to a default将未知的 Encodable 枚举值解码为默认值
【发布时间】:2018-05-17 23:26:23
【问题描述】:

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

{ "name" : "John Smith", "value" : "someValue" }

在 Swift 4 中,“值”应该是一个枚举,而整个对象是一个结构体,例如:

struct MyType {
    name: String?
    value: Value?
}

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

我想我可以创建一个类似的枚举

enum Value {
    case someValue
    case someOtherValue
    case unknown(value: String)
}

但我只是不知道如何反序列化该枚举并使其工作。以前我只是简单地使用了String 枚举,但是反序列化未知值会引发错误。

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

【问题讨论】:

  • 您可以轻松地为任一类型编写自定义的init(coder:)。但是,如果新的枚举值被添加到您自己的后端而不让客户团队知道,这不是技术上解决的问题......
  • 这不是通知,而是向后兼容。可能有些用户只是懒得更新,但我仍然想向他们展示带有新枚举值的条目。我将枚举用于多种用途,例如为某物选择正确的颜色或显示某个图标。然后默认值至少可以显示默认颜色和图标。这应该比简单地不显示任何东西要好。我的主要问题是我反序列化了整个结构数组,因此一个错误的枚举导致没有条目出现
  • 添加一些你想怎么做的代码。

标签: json swift enums deserialization codable


【解决方案1】:

您可以实现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)
}

【讨论】:

  • 啊,所以您的意思是,我不是尝试将一些自定义序列化代码放入枚举中,而是在结构中进行。这是个好主意。我可以在枚举中编写一个小 String -> Value 函数,然后用结构内部的值调用它。谢谢,这对我有帮助
  • 当然..如果有帮助,请接受答案..快乐编码?
猜你喜欢
  • 2011-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-14
  • 1970-01-01
  • 2016-10-10
  • 1970-01-01
相关资源
最近更新 更多