我的困境是我在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
来定义?
感谢您的帮助。
答案 0 :(得分:2)
您不需要两个不同的对象。只需声明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) }
答案 1 :(得分:0)
我实际上喜欢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
更好或更糟,但它是另一种方法。