【问题标题】:Swift decode JSON array of object based on property value type基于属性值类型的对象的 Swift 解码 JSON 数组
【发布时间】:2021-03-21 07:35:54
【问题描述】:

如何解码不同 JSON 对象的数组,其中每个对象的相同属性告诉您使用什么类型来解码它:

let json =
"""
[
    {
        "@type": "FirstObject",
        "number": 1
    },
    {
        "@type": "SecondObject",
        "name": "myName"
    }
]
"""

这里有一些代码based on this similar answer,它可以到达那里,但由于不知道.data 的 CodingKeys 是什么而失败:

struct FirstObject: MyData {
    var dataType: String
    var number: Int
    
    enum CodingKeys: String, CodingKey {
        case dataType = "@type"
        case number
    }
}

struct SecondObject: MyData {
    var dataType: String
    var name: String
    
    enum CodingKeys: String, CodingKey {
        case dataType = "@type"
        case name
    }
}

struct SchemaObj: Decodable
{
    var dataType: String
    var data: MyData
    
    enum CodingKeys: String, CodingKey {
        case data
        case dataType = "@type"
    }
                
    enum ParseError: Error {
        case UnknownSchemaType(Any)
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        dataType = try container.decode(String.self, forKey: .dataType)
        switch dataType {
        case "FirstObject":
            data = try container.decode(FirstObject.self, forKey: .data)
        case "SecondObject":
            data = try container.decode(SecondObject.self, forKey: .data)
        default:
            throw ParseError.UnknownSchemaType(dataType)
        }
    }
}

do {
    let data = Data(json.utf8)
    let result = try JSONDecoder().decode([SchemaObj].self, from: data)
    print(result)
} catch {
    print(error)
}

打印错误是 keyNotFound(CodingKeys(stringValue: "data", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"data\", intValue: nil) (\"data\").", underlyingError: nil))

谢谢

【问题讨论】:

  • 您的 JSON 没有 data 字段。我认为您甚至不需要它,只需从同一个容器中解码,然后让具体类型解码其余的键。

标签: json swift codable decodable


【解决方案1】:

您不需要data 编码密钥。只需根据 JSON 字段的值从同一解码器解码 data 属性:

enum CodingKeys: String, CodingKey {
    case dataType = "@type"
}

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    dataType = try container.decode(String.self, forKey: .dataType)
    switch dataType {
    case "FirstObject":
        data = try FirstObject(from: decoder)
    case "SecondObject":
        data = try SecondObject(from: decoder)
    default:
        throw ParseError.UnknownSchemaType(dataType)
    }
}

如果您打算向该列表添加更多类型,那么 if/else if 可能会变得难以管理,您可以使用查找表来解决此问题:

static let typeMapping: [String: MyData.Type] = [ "FirstObject": FirstObject.self ,
                                                  "SecondObject": SecondObject.self]

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    let dataType = try container.decode(String.self, forKey: .dataType)
    
    guard let classToDecode = Self.typeMapping[dataType] else {
        throw ParseError.UnknownSchemaType(dataType)
    }
    
    self.dataType = dataType
    self.data = try classToDecode.init(from: decoder)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-02
    • 2017-12-07
    • 1970-01-01
    • 1970-01-01
    • 2021-10-30
    • 1970-01-01
    相关资源
    最近更新 更多