如何忽略 codable 中的 nil json 值

How to ignore nil json values in codable

我目前正在收到 Auto-RenewableNon-Renewable 的收据。但是 Non-Renewable 不会返回 expires_date json 键。我怎么能忽略这个。我试图避免使 expires_date 成为可选项。当我将其设为可选时,Apple 会发回回复。有什么方法可以解码 json 而无需将 expires_date 设为可选。

struct Receipt: Codable {

    let expiresDate: String

    private enum CodingKeys: String, CodingKey {
        case expiresDate = "expires_date"
    }
}

现在我可以得到

"No value associated with key CodingKeys(stringValue: \"expires_date\", intValue: nil) (\"expires_date\")."

手动解码如何:

struct Receipt: Codable {

    let expiresDate: String

    private enum CodingKeys: String, CodingKey {
        case expiresDate = "expires_date"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        if let expDate = try? values.decode(String.self, forKey: .expiresDate) {
            self.expiresDate = expDate
        } else {
            self.expiresDate = "sth"
        }
    }
}

示例:

struct Receipt: Codable {

    let expiresDate: String
    let b: String

    private enum CodingKeys: String, CodingKey {
        case expiresDate = "expires_date"
        case b = "b"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        if let expDate = try? values.decode(String.self, forKey: .expiresDate) {
            self.expiresDate = expDate
        } else {
            self.expiresDate = "sth"
        }
        b = try values.decode(String.self, forKey: .b)
    }
}


let a = """
{
    "b": "asdf"
}
""".data(using: .utf8)!
let myStruct = try JSONDecoder().decode(Receipt.self, from: a)
print(myStruct) //Receipt(expiresDate: "sth", b: "asdf")

您必须实现自己的 init(from: Decoder) 并在 nil 合并为默认值之前使用 decodeIfPresent(_:forKey:)

struct Receipt: Codable {
    let expiresDate: String
    
    enum CodingKeys: String, CodingKey {
        case expiresDate = "expires_date"
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)        
        self.expiresDate = try values.decodeIfPresent(String.self, forKey: .expiresDate)
            ?? "1970" //Default value
    }        
}

注意:

  • 如果 Receipt 有更多键值对,那么您也必须手动解码它们。

用法示例:

let data = """
[{
  "expires_date": "2019"
},
{

}]
""".data(using: .utf8)!

do {
    let obj = try JSONDecoder().decode([Receipt].self, from: data)
    print(obj)
}
catch {
    print(error)
}