asp*_*ear 1 json swift codable decodable
如何解码不同 JSON 对象的数组,其中每个对象的相同属性告诉您使用什么类型来解码它:
let json =
"""
[
{
"@type": "FirstObject",
"number": 1
},
{
"@type": "SecondObject",
"name": "myName"
}
]
"""
Run Code Online (Sandbox Code Playgroud)
这是一些基于类似答案的代码,它大部分都可以实现,但失败了,因为它不知道 CodingKeys 的用途.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)
}
Run Code Online (Sandbox Code Playgroud)
打印错误是
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只需根据 JSON 字段的值从同一解码器解码属性即可:
struct SchemaObj: Decodable
{
var dataType: String
var data: MyData
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)
}
}
enum CodingKeys: String, CodingKey {
case dataType = "@type"
}
}
Run Code Online (Sandbox Code Playgroud)
如果您计划向该列表添加更多类型,那么罐子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)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1234 次 |
| 最近记录: |