问题描述
我正在使用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,"datetime": "","p": [
{
"ti": "","pr": {
"value": 120.00,"currency": "EUR"
},"pic": "string"
}
]
}
},{
"pID": "37229890-dcd8-36c4-bb63-e7b174aafeb7","type": "RATE","content": "Rate this app"
}
]
如您所见,“ content”类型的te值可以是简单的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)
}