如何忽略 codable 中的 nil json 值
How to ignore nil json values in codable
我目前正在收到 Auto-Renewable
和 Non-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)
}
我目前正在收到 Auto-Renewable
和 Non-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)
}