Swift解码JSON,对于同一字段有两种可能的类型



我正在使用Alamofire和Codable:处理这个JSON

[
{
"pID": "37229890-dcd8-36c4-bb63-e7b174aafeb7",
"type": "FIRST",
"content": {
"id": "ff64",
"ret": {
"name": "A",
"logoUrl": "hpng"
},
"amo": {
"value": 120.00,
"currency": "EUR"
},
"s": {
"value": 1.20,
"currency": "EUR"
},
"datetime": "",
"p": [
{
"ti": "",
"pr": {
"value": 120.00,
"currency": "EUR"
},
"pic": "string"
}
]
}
},
{
"pID": "37229890-dcd8-36c4-bb63-e7b174aafeb7",
"type": "RATE",
"content": "Rate this app"
}
]

正如你所看到的,类型为";内容";可以是简单的String或Struct。

我尝试了一个自定义解码器,并有一个顶部结构,但我无法实现这个问题的解决方案。

解决这个问题的最佳方法是什么?

这是您所期望的吗?

let json = """
[
{
"type": "type1",
"content": {
"id": "ff64",
"title": "a title"
}
},
{
"type": "type2",
"content": "Rate this app"
}
]
"""
struct Type1: Decodable {
let id: String
let title: String
}
typealias Type2 = String
enum Content: Decodable {
case type1(Type1)
case type2(Type2)
enum ContentType: String, Decodable {
case type1
case type2
}
enum Keys: String, CodingKey {
case type
case content
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Keys.self)
let type = try container.decode(ContentType.self, forKey: .type)
switch type {
case .type1:
let content = try container.decode(Type1.self, forKey: .content)
self = .type1(content)
case .type2:
let content = try container.decode(Type2.self, forKey: .content)
self = .type2(content)
}
}
}
let result = try JSONDecoder().decode([Content].self, from: json.data(using: .utf8)!)

您可以应用AnyCodable自定义解码器方法来解码您需要的类型,例如:

struct AnyCodable : Codable {
let value: Any

func encode(to encoder: Encoder) throws {
}

init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()

if let str = try? container.decode(String.self) {
value = str
} else if let content = try? container.decode(Content.self) {
value = content
} else {
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Value cannot be decoded!")
}
}
}
struct Content : Codable {
let id: String
}
struct Item : Codable {
let content: AnyCodable
}

如何使用:

do {
let items = try JSONDecoder().decode([Item].self, from: json.data(using: .utf8)!);
for item in items {
if let content = item.content.value as? String {
print(content)
}
else if let content = item.content.value as? Content {
print(content.id)
}
}
}
catch {
print(error)
}

最新更新