如何解决Swift基于属性值类型解码对象的JSON数组
如何解码不同 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))
谢谢
解决方法
您不需要 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)
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。