Swift json 动态键响应的解析问题
Swift parsing issue of json response of dynamic keys
下面的代码只解析了数组中的一个对象,但是在json响应中有两个对象。
我不明白为什么这段代码只解析一个对象而不解析另一个对象。当下面的代码解析动态键名称为“40”的第二个对象时,我得到了 nil 值。
Json结构
这是我想使用 Codable class 解析的 json 结构。
{
"search_result": "",
"related_product_price_info": [
{
"39": {
"price": 1000.0,
"discount_percentage": 10.0,
"related_product_group_id": 1039,
"discounted_price": 900.0
}
},
{
"40": {
"price": 999.0,
"discount_percentage": 10.0,
"related_product_group_id": 1040,
"discounted_price": 899.1
}
}
]
}
型号
struct ProductSearchResult: Codable {
let searchResult: String?
let relatedProductPriceInfo: [RelatedProductPriceInfo]?
enum CodingKeys: String, CodingKey {
case searchResult = "search_result"
case relatedProductPriceInfo = "related_product_price_info"
}
}
struct RelatedProductPriceInfo: Codable {
var relatedProductPrice: RelatedProductPrice?
private struct DynamicCodingKeys: CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
return nil
}
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: DynamicCodingKeys.self)
for key in container.allKeys {
guard let decodedObject = try? container.decode(RelatedProductPrice.self, forKey: DynamicCodingKeys(stringValue: key.stringValue)!) else{
continue
}
relatedProductPrice = decodedObject
}
}
}
}
正在解析
let result = try? JSONDecoder().decode(ProductSearchResult.self, from: data)
输出
我只能解析一个对象 (key = "39") 而不能解析另一个对象 (key="40")
▿ Optional<ProductSearchResult>
▿ some : ProductSearchResult
- searchResult : ""
▿ relatedProductPriceInfo : Optional<Array<RelatedProductPriceInfo>>
▿ some : 2 elements
▿ 0 : RelatedProductPriceInfo
▿ relatedProductPrice : Optional<RelatedProductPrice>
▿ some : RelatedProductPrice
- price : 1000
- discountPercentage : 10
- relatedProductGroupID : 1039
- discountedPrice : 900
▿ 1 : RelatedProductPriceInfo
- relatedProductPrice : nil
您的数据结构不太正确。 relatedProductPriceInfo 的主体实际上是一个字典数组。如果你正确映射它,你可以大大简化事情,如果你在解码器上设置密钥解码选项,你可以避免声明所有 CodingKeys。
作为一个基本的解决方案(你应该更好地捕获错误等)
struct ProductSearchResult: Codable {
let searchResult: String?
let relatedProductPriceInfo: [[String: PriceDetail]]
}
struct PriceDetail: Codable {
let price: Double
let discountPercentage: Double
let relatedProductGroupId: Double
let discountedPrice: Double
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let data = Data(JSON.utf8)
let output = try decoder.decode(ProductSearchResult.self, from: data)
//quick and dirty printing of output
output.relatedProductPriceInfo.forEach{print([=10=].keys, [=10=].values)}
这会关闭输出
["39"] [__lldb_expr_70.PriceDetail(price: 1000.0, discountPercentage: 10.0, relatedProductGroupId: 1039.0, discountedPrice: 900.0)]
["40"] [__lldb_expr_70.PriceDetail(price: 999.0, discountPercentage: 10.0, relatedProductGroupId: 1040.0, discountedPrice: 899.1)]
在现实世界中,您可能随后想要展平字典数组,或使用中间结构来包装它们,这一切都取决于您对各种数据位的用例。
下面的代码只解析了数组中的一个对象,但是在json响应中有两个对象。 我不明白为什么这段代码只解析一个对象而不解析另一个对象。当下面的代码解析动态键名称为“40”的第二个对象时,我得到了 nil 值。
Json结构
这是我想使用 Codable class 解析的 json 结构。
{
"search_result": "",
"related_product_price_info": [
{
"39": {
"price": 1000.0,
"discount_percentage": 10.0,
"related_product_group_id": 1039,
"discounted_price": 900.0
}
},
{
"40": {
"price": 999.0,
"discount_percentage": 10.0,
"related_product_group_id": 1040,
"discounted_price": 899.1
}
}
]
}
型号
struct ProductSearchResult: Codable {
let searchResult: String?
let relatedProductPriceInfo: [RelatedProductPriceInfo]?
enum CodingKeys: String, CodingKey {
case searchResult = "search_result"
case relatedProductPriceInfo = "related_product_price_info"
}
}
struct RelatedProductPriceInfo: Codable {
var relatedProductPrice: RelatedProductPrice?
private struct DynamicCodingKeys: CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
return nil
}
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: DynamicCodingKeys.self)
for key in container.allKeys {
guard let decodedObject = try? container.decode(RelatedProductPrice.self, forKey: DynamicCodingKeys(stringValue: key.stringValue)!) else{
continue
}
relatedProductPrice = decodedObject
}
}
}
}
正在解析
let result = try? JSONDecoder().decode(ProductSearchResult.self, from: data)
输出
我只能解析一个对象 (key = "39") 而不能解析另一个对象 (key="40")
▿ Optional<ProductSearchResult>
▿ some : ProductSearchResult
- searchResult : ""
▿ relatedProductPriceInfo : Optional<Array<RelatedProductPriceInfo>>
▿ some : 2 elements
▿ 0 : RelatedProductPriceInfo
▿ relatedProductPrice : Optional<RelatedProductPrice>
▿ some : RelatedProductPrice
- price : 1000
- discountPercentage : 10
- relatedProductGroupID : 1039
- discountedPrice : 900
▿ 1 : RelatedProductPriceInfo
- relatedProductPrice : nil
您的数据结构不太正确。 relatedProductPriceInfo 的主体实际上是一个字典数组。如果你正确映射它,你可以大大简化事情,如果你在解码器上设置密钥解码选项,你可以避免声明所有 CodingKeys。
作为一个基本的解决方案(你应该更好地捕获错误等)
struct ProductSearchResult: Codable {
let searchResult: String?
let relatedProductPriceInfo: [[String: PriceDetail]]
}
struct PriceDetail: Codable {
let price: Double
let discountPercentage: Double
let relatedProductGroupId: Double
let discountedPrice: Double
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let data = Data(JSON.utf8)
let output = try decoder.decode(ProductSearchResult.self, from: data)
//quick and dirty printing of output
output.relatedProductPriceInfo.forEach{print([=10=].keys, [=10=].values)}
这会关闭输出
["39"] [__lldb_expr_70.PriceDetail(price: 1000.0, discountPercentage: 10.0, relatedProductGroupId: 1039.0, discountedPrice: 900.0)]
["40"] [__lldb_expr_70.PriceDetail(price: 999.0, discountPercentage: 10.0, relatedProductGroupId: 1040.0, discountedPrice: 899.1)]
在现实世界中,您可能随后想要展平字典数组,或使用中间结构来包装它们,这一切都取决于您对各种数据位的用例。