我的应用程序,就像很多应用程序一样,从API中检索JSON并使用Swift 4中的新Codable协议进行转换。但是,有时API会给我发送意想不到的垃圾。不正确的类型,数组中只有null之类的东西。
问题是所涉及的对象可能是大的和复杂的,当我解析一个子对象而它失败时,整个对象就会失败,一直到根。我举了一个非常简单的操场例子来说明这个概念;实际的对象要复杂得多。
let goodJSON = """
{
"name": "Fiona Glenanne",
"vehicles": [
{
"make": "Saab",
"model": "9-3",
"color": "Black"
},
{
"make": "Hyundai",
"model": "Genesis",
"color": "Blue"
}
]
}
"""
let goodJSONData = goodJSON.data(using: .utf8)!
let badJSON = """
{
"name": "Michael Westen",
"vehicles": {
"make": "Dodge",
"model": "Charger",
"color": "Black"
}
}
"""
let badJSONData = badJSON.data(using: .utf8)!
struct Character: Codable {
let name: String
let vehicles: [Vehicle]
}
struct Vehicle: Codable {
let make: String
let model: String
let color: String
}
do {
let goodCharacter = try JSONDecoder().decode(Character.self, from: goodJSONData)
print(goodCharacter)
} catch {
print(error)
}
do {
let badCharacter = try JSONDecoder().decode(Character.self, from: badJSONData)
print(badCharacter)
} catch DecodingError.typeMismatch(let type, let context) {
print("Got \(type); \(context.debugDescription) ** Path:\(context.codingPath)")
} catch {
print("Caught a different error: \(error)")
}输出:
Character(name: "Fiona Glenanne", vehicles: [__lldb_expr_20.Vehicle(make: "Saab", model: "9-3", color: "Black"), __lldb_expr_20.Vehicle(make: "Hyundai", model: "Genesis", color: "Blue")])
Got Array<Any>; Expected to decode Array<Any> but found a dictionary instead. ** Path:[CodingKeys(stringValue: "vehicles", intValue: nil)]vehicles应该是一个对象数组,但在badJSON的情况下,它是一个单独的对象,这会导致.typeMismatch异常并在那里终止解析。
我正在寻找的是一种允许这样的错误只为子对象终止解析并允许父对象解析继续的方法。我希望以一种通用的方式这样做,所以我不需要专门处理我的应用程序中的每一个对象,就可以专门处理API提供的任何坏数据。我不确定是否有办法解决这个问题,我没有任何运气,但如果有,我的生活质量肯定会得到改善。谢谢!
发布于 2018-09-18 20:54:50
您可以尝试自定义init(来自解码器:解码器),如注释中所建议的,
struct Character: Codable {
let name: String
let vehicles: [Vehicle]
private enum CodingKeys: String, CodingKey { case name, vehicles }
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
do {
let vehicle = try container.decode(Vehicle.self, forKey: .vehicles)
vehicles = [vehicle]
} catch DecodingError.typeMismatch {
vehicles = try container.decode([Vehicle].self, forKey: .vehicles)
}
}https://stackoverflow.com/questions/52393915
复制相似问题