Ниже мой JSON, и я не могу декодировать (используя CodingKeys) Данные в ключе регионы представляют собой Словарь («IN-WB», «IN-DL» и т.д.), поскольку ключи являются динамическими, их можно более или менее изменять.
Пожалуйста, помогите мне разобрать то же самое с помощью Decodable и Codable.
Все данные должны быть в одной модели.
{ "provider_code": "AIIN", "name": "Jio India", "regions": [ { "IN-WB": "West Bengal" }, { "IN-DL": "Delhi NCR" }, { "IN-TN": "Tamil Nadu" }, { "IN": "India" } ] }
Что вы имеете в виду под «Все данные должны быть в одной модели». ?)
Просто используйте Словарь для регионов.
struct Locations: Codable {
let providerCode: String
let name: String
let regions: [[String: String]]
enum CodingKeys: String, CodingKey {
case providerCode = "provider_code"
case name, regions
}
}
Вы не можете создать конкретную модель для регионов, так как не знаете названия свойств.
Но вы можете создать регион (идентификатор, имя). Почему бы и нет, с помощью decoder.unkeyedContainer () или динамического ключа.
вы не знаете ключ JSON? поэтому JSONDecoder не сможет этого сделать, вам нужно будет переопределить init(decoder:_)
для анализа как [[String: String]]
, зациклить каждый найденный элемент и инициализировать регион, например Region(key, value)
Один из возможных подходов, без словаря. Но сначала надо найти ключ)
Мне нравится этот стиль, так как мы можем использовать регионы с самого начала.
// example data.
let string = "{\"provider_code\":\"AIIN\",\"name\":\"Jio India\",\"regions\":[{\"IN-WB\":\"West Bengal\"},{\"IN-DL\":\"Delhi NCR\"},{\"IN-TN\":\"Tamil Nadu\"},{\"IN\":\"India\"}]}"
let data = string.data(using: .utf8)!
// little helper
struct DynamicGlobalKey: CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int? { return nil }
init?(intValue: Int) { return nil }
}
// model
struct Location: Decodable {
let providerCode: String
let name: String
let regions: [Region]
}
extension Location {
struct Region: Decodable {
let key: String
let name: String
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: DynamicGlobalKey.self)
key = container.allKeys.first!.stringValue
name = try container.decode(String.self, forKey: container.allKeys.first!)
}
}
}
// example of decoding.
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let location = try decoder.decode(Location.self, from: data)
Вы отвечаете за JSON? Учтите, что массив словарей, содержащий только одну пару ключ-значение соответственно, является очень неэффективной моделью. Лучше отправьте словарь, например
{ "code" : "IN-WB", "name" : "West Bengal"}
, это, кстати, решает вашу проблему.