[英]Multiple codable object types out of a single JSON return
My dilemma is I'm receiving two different object types from one table in a JSON response. 我的困境是我从JSON响应的一个表中接收了两种不同的对象类型。 Here is an example of the response of both types in a return.
这是返回中两种类型的响应的示例。
"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
}
]
What we're hoping to do is create two different types of objects here. 我们希望做的是在这里创建两种不同类型的对象。 A
textOnlyItem
, and a imageWithTextItem
. 一个
textOnlyItem
和一个imageWithTextItem
。
Is there a way to create one as a subclass or extension that can be keyed off of a Bool
defined by whether imageName
is null
or not? 有没有一种方法可以将其创建为可以通过
imageName
是否为null
定义的Bool
禁用的子类或扩展?
Thanks for any help all. 谢谢大家的帮助。
You don't need two different objects. 您不需要两个不同的对象。 Just declare
imageName
and textItems
as optional, this handles the null
case. 只需将
imageName
和textItems
声明为可选,即可处理null
情况。
You can simply check whether imageName
is nil
您可以简单地检查
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) }
I actually like vadian's approach, of one type. 我实际上喜欢vadian的一种方法。 But I gather that would require significant refactoring in your situation.
但我认为这将需要对您的情况进行重大重构。
The other approach is to just use JSONSerialization
and build your heterogeneous array manually. 另一种方法是仅使用
JSONSerialization
并手动构建异构数组。 JSONSerialization
isn't deprecated, it just doesn't do it automatically like JSONDecoder
. JSONSerialization
并没有被弃用,只是没有像JSONDecoder
这样自动JSONDecoder
。
Another approach is to use JSONDecoder
, writing custom initializer that tries to decode it as ImageItem
, and if that fails, try decoding it as TextItem
: 另一种方法是使用
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
}
}
Then: 然后:
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)
I'm not convinced this is any better or worse than just using JSONSerialization
, but it's another approach. 我不相信这比仅使用
JSONSerialization
更好或更糟,但这是另一种方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.