Swift 4 从自定义 JSON 对象解码为不同的模型

Ale*_*sky 0 json swift

我有一个生成不同 json 对象的 websocket。对象不能包含任何公共字段

{
    "type": "apple",
    "kind": "fruit",
    "eatable": true
}
{
    "item": "key",
    "active": true 
}
{
    "tool": "screwdriver",
    "original": "toolBox",
    "cross-head": true
}
Run Code Online (Sandbox Code Playgroud)

我有一个它们的类列表(它们可能包含一些逻辑),所以我需要解析它以映射一些具有某种层次结构的模型,例如尝试解析水果如果它们失败尝试解析键如果它们尝试解析工具箱失败。有时我需要添加一些新类来解析一些对象和一些新字段到现有类。
如何组织采摘类进行解析?

更新

  1. 我无法控制后端数据,因此无法向我拥有的 JSON 添加任何字段。
  2. 对象一次一个。我对其中的大多数都有单独的类模型。问题是选择正确的类来映射 JSON 字段。

Zap*_*hod 5

你可以这样做:

首先你声明你的类型符合Decodable协议:

struct Fruit : Decodable {
    let type : String
    let kind : String
    let eatable : Bool
}

struct Tool : Decodable {
    let tool : String
    let original : String
    let crossHead : Bool

    enum CodingKeys: String, CodingKey {
        case tool = "tool"
        case original = "original"
        case crossHead = "cross-head"
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你扩展Decodable到“反向”通用性的使用:

extension Decodable {
    static func decode(data : Data, decoder : JSONDecoder = JSONDecoder()) -> Self? {
        return try? decoder.decode(Self.self, from: data)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后JSONDecoder,您可以扩展以在要测试的类型中尝试可解码类型:

extension JSONDecoder {
    func decode(possibleTypes : [Decodable.Type], from data: Data) -> Any? {
        for type in possibleTypes {
            if let value = type.decode(data: data, decoder: self) {
                return value
            }
        }        
        return nil
    }
}
Run Code Online (Sandbox Code Playgroud)

最终您指定要尝试解码的类型:

let decodableTypes : [Decodable.Type] = [Fruit.self, Tool.self]
Run Code Online (Sandbox Code Playgroud)

然后您可以使用它来解码您的 JSON:

let jsonString = """
    {
        "tool": "screwdriver",
        "original": "toolBox",
        "cross-head": true
    }
    """
let jsonData = jsonString.data(using: .utf8)!

let myUnknownObject = JSONDecoder().decode(possibleTypes: decodableTypes, from: jsonData)
Run Code Online (Sandbox Code Playgroud)

瞧!!!

现在decodableTypes,只要符合Decodable协议,您就可以根据需要添加任意数量的类型。

这不是最好的方法,因为如果您有很多类型,它就不是最佳方法,但是这样您就不需要在数据中添加区分字段。