单个 JSON 返回中的多个可编码对象类型
Posted
技术标签:
【中文标题】单个 JSON 返回中的多个可编码对象类型【英文标题】:Multiple codable object types out of a single JSON return 【发布时间】:2018-01-22 19:33:42 【问题描述】:我的困境是我在 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
。
有没有一种方法可以创建一个子类或扩展,可以从 Bool
中删除,由 imageName
是否为 null
定义?
感谢大家的帮助。
【问题讨论】:
【参考方案1】:您不需要两个不同的对象。只需将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)
【讨论】:
问题是我确实需要多个对象。在项目中,每个实例都有大量的实例(以前他们使用硬编码的数据源,并且有两个对象。现在两个对象都有一个返回)所以我们需要提取每个对象类型,或者重组大量他们的应用程序。如果无法在此级别将它们分开,这是有可能的。 那你得写一个自定义的初始化器。【参考方案2】:我实际上喜欢 vadian 的一种方法。但我认为这需要对您的情况进行重大重构。
另一种方法是只使用JSONSerialization
并手动构建您的异构数组。 JSONSerialization
没有被弃用,它只是不像 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
更好或更差,但这是另一种方法。
【讨论】:
嗨,Rob,感谢您的回复。经过一些研究,我认为我希望的确切功能在技术上是不可能的。以上是关于单个 JSON 返回中的多个可编码对象类型的主要内容,如果未能解决你的问题,请参考以下文章
Swift:如何将可编码类型作为函数输入传递给编码或解码 json
如何将单个 .NET 类型映射到 ElasticSearch/NEST 中的多个嵌套对象类型?