首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >可快速编码:嵌套对象错误后继续解析对象

可快速编码:嵌套对象错误后继续解析对象
EN

Stack Overflow用户
提问于 2018-09-18 20:08:22
回答 1查看 266关注 0票数 0

我的应用程序,就像很多应用程序一样,从API中检索JSON并使用Swift 4中的新Codable协议进行转换。但是,有时API会给我发送意想不到的垃圾。不正确的类型,数组中只有null之类的东西。

问题是所涉及的对象可能是大的和复杂的,当我解析一个子对象而它失败时,整个对象就会失败,一直到根。我举了一个非常简单的操场例子来说明这个概念;实际的对象要复杂得多。

代码语言:javascript
复制
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)")
}

输出:

代码语言:javascript
复制
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提供的任何坏数据。我不确定是否有办法解决这个问题,我没有任何运气,但如果有,我的生活质量肯定会得到改善。谢谢!

EN

回答 1

Stack Overflow用户

发布于 2018-09-18 20:54:50

您可以尝试自定义init(来自解码器:解码器),如注释中所建议的,

代码语言:javascript
复制
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)
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52393915

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档