如果字典数组缺少一个键,如何编写 Codable
How to write Codable if array of dictionary missing one key
在服务器响应中有时会丢失 "tags" 键。我们必须如何为此响应编写可编码结构。
[
{
"product_id": 10
"product_name": "Bulb"
"tags": ["x", "y", "z"]
},
{
"product_id": 11
"product_name": "Wire"
}
]
像这样解码
do {
// decoding...
let product_model = try JSONDecoder().decode([ProductItem].self, from: data)
} catch let error {
print("Product list error(decoder): \(error.localizedDescription)")
}
// 产品结构
struct ProductItem: Codable {
// variables
let product_id: String?
let product_name: String?
let tags: [String]?
// alternative keys...
private enum CodingKeys: String, CodingKey {
case product_id
case product_name
case tags // what i have to do here
}
}
看来你JSON不正确。它看起来应该类似于这个:
[
{
"product_id": 10,
"product_name": "Bulb",
"tags": ["x", "y", "z"]
},
{
"product_id": 11,
"product_name": "Wire"
}
]
为此,您的结构应类似于:
struct ProductItem: Codable {
// variables
let product_id: Int
let product_name: String
let tags: [String]?
}
如果结构中的变量与 JSON 对象中的键同名,则不必提供 CodingKeys
。另外,请记住 "product_id": 10,
是一个数字,因此您应该使用 Int
而不是 String
.
你的 JSON 少了一些逗号,正确的 JSON 是:
[
{
"product_id": 10,
"product_name": "Bulb",
"tags": ["x", "y", "z"]
},
{
"product_id": 11,
"product_name": "Wire"
}
]
您代码中的 product_id
是一个 String
,而在您的 JSON 中,它是一个数字。
Swift 实际上可以像这样处理丢失的键,只要您将 属性 设为可选,您在此处已正确完成。当JSON中没有key时,tags
会被赋值为nil
。因此,除了将 product_id
更改为 Int
.
之外,您实际上不需要做任何其他事情
如果您在解码时使用 convertFromSnakeCase
选项,您的 属性 名称也可以重命名为更 Swifty:
struct ProductItem: Codable {
let productId: Int?
let productName: String?
let tags: [String]?
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decoded = try! decoder.decode([ProductItem].self, from: data)
print(decoded[1].tags) // nil
@dahiya_boy 谢谢。下面的代码工作正常。
struct ProductItem : Codable {
let productId : Int?
let productName : String?
let tags : [String]?
enum CodingKeys: String, CodingKey {
case productId = "product_id"
case productName = "product_name"
case tags = "tags"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
productId = try values.decodeIfPresent(Int.self, forKey: .productId)
productName = try values.decodeIfPresent(String.self, forKey: .productName)
tags = try values.decodeIfPresent([String].self, forKey: .tags)
}
}
在服务器响应中有时会丢失 "tags" 键。我们必须如何为此响应编写可编码结构。
[
{
"product_id": 10
"product_name": "Bulb"
"tags": ["x", "y", "z"]
},
{
"product_id": 11
"product_name": "Wire"
}
]
像这样解码
do {
// decoding...
let product_model = try JSONDecoder().decode([ProductItem].self, from: data)
} catch let error {
print("Product list error(decoder): \(error.localizedDescription)")
}
// 产品结构
struct ProductItem: Codable {
// variables
let product_id: String?
let product_name: String?
let tags: [String]?
// alternative keys...
private enum CodingKeys: String, CodingKey {
case product_id
case product_name
case tags // what i have to do here
}
}
看来你JSON不正确。它看起来应该类似于这个:
[
{
"product_id": 10,
"product_name": "Bulb",
"tags": ["x", "y", "z"]
},
{
"product_id": 11,
"product_name": "Wire"
}
]
为此,您的结构应类似于:
struct ProductItem: Codable {
// variables
let product_id: Int
let product_name: String
let tags: [String]?
}
如果结构中的变量与 JSON 对象中的键同名,则不必提供 CodingKeys
。另外,请记住 "product_id": 10,
是一个数字,因此您应该使用 Int
而不是 String
.
你的 JSON 少了一些逗号,正确的 JSON 是:
[
{
"product_id": 10,
"product_name": "Bulb",
"tags": ["x", "y", "z"]
},
{
"product_id": 11,
"product_name": "Wire"
}
]
您代码中的 product_id
是一个 String
,而在您的 JSON 中,它是一个数字。
Swift 实际上可以像这样处理丢失的键,只要您将 属性 设为可选,您在此处已正确完成。当JSON中没有key时,tags
会被赋值为nil
。因此,除了将 product_id
更改为 Int
.
如果您在解码时使用 convertFromSnakeCase
选项,您的 属性 名称也可以重命名为更 Swifty:
struct ProductItem: Codable {
let productId: Int?
let productName: String?
let tags: [String]?
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decoded = try! decoder.decode([ProductItem].self, from: data)
print(decoded[1].tags) // nil
@dahiya_boy 谢谢。下面的代码工作正常。
struct ProductItem : Codable {
let productId : Int?
let productName : String?
let tags : [String]?
enum CodingKeys: String, CodingKey {
case productId = "product_id"
case productName = "product_name"
case tags = "tags"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
productId = try values.decodeIfPresent(Int.self, forKey: .productId)
productName = try values.decodeIfPresent(String.self, forKey: .productName)
tags = try values.decodeIfPresent([String].self, forKey: .tags)
}
}