一尘不染

使用值有时为Int且有时为String的可编码

swift

我有一个API,有时会id以Int的形式在JSON中返回特定的键值(在本例中为),而有时它会返回与String相同的键值。如何使用可编码解析该JSON?

struct GeneralProduct: Codable {
    var price: Double!
    var id: String?
    var name: String!

    private enum CodingKeys: String, CodingKey {
        case price = "p"
        case id = "i"
        case name = "n"
    }

    init(price: Double? = nil, id: String? = nil, name: String? = nil) {
        self.price = price
        self.id = id
        self.name = name
    }
}

我不断收到此错误消息:Expected to decode String but found a number instead。它返回数字的原因是因为id字段为空,并且当id字段为空时,默认情况下返回0作为ID,可编码的ID标识为数字。我基本上可以忽略ID密钥,但是codable并不能让我选择忽略它。处理此问题的最佳方法是什么?

这是JSON。超级简单

加工

{
  "p":2.12,
  "i":"3k3mkfnk3",
  "n":"Blue Shirt"
}

错误-由于系统中没有id,因此它默认返回0,可编码的代码显然将其视为与字符串相反的数字。

{
  "p":2.19,
  "i":0,
  "n":"Black Shirt"
}

阅读 382

收藏
2020-07-07

共1个答案

一尘不染

struct GeneralProduct: Codable {
    var price: Double?
    var id: String?
    var name: String?
    private enum CodingKeys: String, CodingKey {
        case price = "p", id = "i", name = "n"
    }
    init(price: Double? = nil, id: String? = nil, name: String? = nil) {
        self.price = price
        self.id = id
        self.name = name
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        price = try container.decode(Double.self, forKey: .price)
        name = try container.decode(String.self, forKey: .name)
        do {
            id = try String(container.decode(Int.self, forKey: .id))
        } catch DecodingError.typeMismatch {
            id = try container.decode(String.self, forKey: .id)
        }
    }
}

let json1 = """
{
"p":2.12,
"i":"3k3mkfnk3",
"n":"Blue Shirt"
}
"""

let json2 = """
{
"p":2.12,
"i":0,
"n":"Blue Shirt"
}
"""

do {
    let product = try JSONDecoder().decode(GeneralProduct.self, from: Data(json2.utf8))
    print(product.price ?? "nil")
    print(product.id ?? "nil")
    print(product.name ?? "nil")
} catch {
    print(error)
}

编辑/更新

您还nil可以id在api返回时简单地分配给您0

do {
    let value = try String(container.decode(Int.self, forKey: .id))
    id = value == "0" ? nil : value
} catch DecodingError.typeMismatch {
    id = try container.decode(String.self, forKey: .id)
}
2020-07-07