Swift 根据 属性 值类型解码 JSON 对象数组
Swift decode JSON array of object based on property value type
如何解码不同 JSON 对象的数组,其中每个对象上的相同 属性 告诉您使用什么类型来解码它:
let json =
"""
[
{
"@type": "FirstObject",
"number": 1
},
{
"@type": "SecondObject",
"name": "myName"
}
]
"""
这里是一些代码 ,它完成了大部分工作,但失败了,因为它不知道 .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
可能会变得难以管理,您可以使用查找 table 来解决此问题:
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)
}
如何解码不同 JSON 对象的数组,其中每个对象上的相同 属性 告诉您使用什么类型来解码它:
let json =
"""
[
{
"@type": "FirstObject",
"number": 1
},
{
"@type": "SecondObject",
"name": "myName"
}
]
"""
这里是一些代码 .data
:
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
可能会变得难以管理,您可以使用查找 table 来解决此问题:
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)
}