![](/img/trans.png)
[英]Using Codable when JSON input represents multiple subclasses of a Codable type
[英]Multiple codable object types out of a single JSON return
我的困境是我从JSON响应的一个表中接收了两种不同的对象类型。 这是返回中两种类型的响应的示例。
"supplementaryItems": [
{
"header": "Doodle",
"subHeader": "It's a drawing.",
"slideID": 4,
"imageName": null,
"textItems": null,
"sortOrder": 0
},
{
"header": "Cell Phones",
"subHeader": "No phones please",
"slideID": 8,
"imageName": "welcome_icon_cellphones",
"textItems": ["first","second","third"],
"sortOrder": 1
}
]
我们希望做的是在这里创建两种不同类型的对象。 一个textOnlyItem
和一个imageWithTextItem
。
有没有一种方法可以将其创建为可以通过imageName
是否为null
定义的Bool
禁用的子类或扩展?
谢谢大家的帮助。
您不需要两个不同的对象。 只需将imageName
和textItems
声明为可选,即可处理null
情况。
您可以简单地检查imageName
是否为nil
let jsonString = """
{"supplementaryItems": [
{
"header": "Doodle",
"subHeader": "It's a drawing.",
"slideID": 4,
"imageName": null,
"textItems": null,
"sortOrder": 0
},
{
"header": "Cell Phones",
"subHeader": "No phones please",
"slideID": 8,
"imageName": "welcome_icon_cellphones",
"textItems": ["first","second","third"],
"sortOrder": 1
}
]
}
"""
struct Root : Decodable {
let supplementaryItems : [SupplementaryItem]
}
struct SupplementaryItem : Decodable {
let header : String
let subHeader : String
let slideID : Int
let imageName : String?
let textItems : [String]?
let sortOrder : Int
}
do {
let data = Data(jsonString.utf8)
let result = try JSONDecoder().decode(Root.self, from: data)
for item in result.supplementaryItems {
if let imageName = item.imageName {
print(imageName + " has text items")
} else {
print(item.header + " has no text items")
}
}
} catch { print(error) }
我实际上喜欢vadian的一种方法。 但我认为这将需要对您的情况进行重大重构。
另一种方法是仅使用JSONSerialization
并手动构建异构数组。 JSONSerialization
并没有被弃用,只是没有像JSONDecoder
这样自动JSONDecoder
。
另一种方法是使用JSONDecoder
,编写尝试将其解码为ImageItem
自定义初始化程序,如果失败,请尝试将其解码为TextItem
:
protocol SupplementaryItem {
var header: String { get }
var subHeader: String { get }
var slideID: Int { get }
var sortOrder: Int { get }
var textItems: [String]? { get }
}
struct TextItem: SupplementaryItem, Codable {
let header: String
let subHeader: String
let slideID: Int
let sortOrder: Int
let textItems: [String]?
}
struct ImageItem: SupplementaryItem, Codable {
let header: String
let subHeader: String
let slideID: Int
let sortOrder: Int
let textItems: [String]?
let imageName: String
}
struct ResponseObject: Decodable {
let supplementaryItems: [SupplementaryItem]
enum CodingKeys: String, CodingKey {
case supplementaryItems
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
var container = try values.nestedUnkeyedContainer(forKey: .supplementaryItems)
if container.count == nil {
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Expected array for supplementaryItems")
}
var items = [SupplementaryItem]()
while !container.isAtEnd {
if let item = try? container.decodeIfPresent(ImageItem.self), let imageItem = item {
items.append(imageItem)
} else {
let textItem = try container.decode(TextItem.self)
items.append(textItem)
}
}
supplementaryItems = items
}
}
然后:
let string = """
{
"supplementaryItems": [
{
"header": "Doodle",
"subHeader": "It's a drawing.",
"slideID": 4,
"imageName": "foo",
"textItems": null,
"sortOrder": 0
},
{
"header": "Cell Phones",
"subHeader": "No phones please",
"slideID": 8,
"imageName": "welcome_icon_cellphones",
"textItems": ["first","second","third"],
"sortOrder": 1
}
]
}
"""
let data = string.data(using: .utf8)!
let json = try! JSONDecoder().decode(ResponseObject.self, from: data)
print(json)
我不相信这比仅使用JSONSerialization
更好或更糟,但这是另一种方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.