#json #swift #parsing #dynamic #key
Вопрос:
Приведенный ниже код анализирует только один объект в массиве, но в ответе json есть два объекта. Я не понимаю, почему этот код анализирует только один объект, а не другой. Я получил нулевое значение, когда ниже кода проанализировал второй объект, имя динамических ключей которого «40».
Структура Json
Это структура 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)
Выход
Я могу проанализировать только один объект (ключ = «39»), но не другой (ключ=»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
Комментарии:
1. Измените
let relatedProductPriceInfo: [String: RelatedProductPriceInfo]
и удалите все лишние вещи, которые у вас есть.2. Нет, это не работает. я прошел
result = nil
этим путем. @Йоаким Дэниелсон3. Да, я немного поторопился там,
let relatedProductPriceInfo: [[String: RelatedProductPrice]]
4. Нет, все еще есть то же самое
result = nil
5. Для меня это прекрасно работает. Общие рекомендации используйте
try
вместоtry?
необязательных свойств и избегайте их, и вы можете получить большую помощь, напечатав любые ошибки с помощьюdo {...} catch { print(error) }
Ответ №1:
Ваша структура данных не совсем правильная. Тело relatedProductPriceInfo на самом деле представляет собой массив словарей. Если вы правильно сопоставите это, вы сможете значительно упростить задачу, и если вы установите опцию декодирования ключей в декодере, вам не придется объявлять все кодовые клавиши.
Как простое решение (вы должны лучше улавливать ошибки и т. Д.)
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)]
В реальном мире вам может потребоваться сгладить массив словарей или использовать промежуточную структуру для их переноса, все зависит от вашего варианта использования для различных битов данных.