【问题标题】:Swift parsing issue of json response of dynamic keys快速解析动态键的json响应问题
【发布时间】:2021-11-14 07:01:12
【问题描述】:

以下代码仅解析数组中的一个对象,但在 json 响应中有两个对象。 我不明白为什么这段代码只解析一个对象而不是另一个。当下面的代码解析动态键名称为“40”的第二个对象时,我得到了 nil 值。

Json 结构

这是我想使用 Codable 类解析的 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

【问题讨论】:

  • 更改为 let relatedProductPriceInfo: [String: RelatedProductPriceInfo] 并删除所有多余的东西。
  • 不,它不起作用。我通过这种方式得到了result = nil。 @Joakim Danielson
  • 是的,我有点快,let relatedProductPriceInfo: [[String: RelatedProductPrice]]
  • 没有还是一样的result = nil
  • 它对我来说很好用。一般建议使用try 而不是try? 并避免可选属性,您可以通过使用do {...} catch { print(error) } 打印任何错误来获得很多帮助

标签: json swift parsing dynamic key


【解决方案1】:

您的数据结构不太正确。 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($0.keys, $0.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)]

在现实世界中,您可能想要展平字典数组,或使用中间结构来包装它们,这一切都取决于您对各种数据位的用例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2023-03-23
    • 1970-01-01
    • 2020-02-22
    • 1970-01-01
    相关资源
    最近更新 更多