Если вам это нужно несколько раз, вы можете создать свою собственную общую структуру, которая декодирует любой найденный ключ:
struct Nester<T: Decodable>: Decodable {
let elements: [T]
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let key = container.allKeys.first {
elements = try container.decode([T].self, forKey: key)
} else {
// we run into an empty dictionary, let's signal this
throw DecodingError.typeMismatch([String:Any].self, DecodingError.Context(codingPath: [], debugDescription: "Expected to find at least one key"))
}
}
// A coding key that accepts whatever string value it is given
struct CodingKeys: CodingKey {
let stringValue: String
var intValue: Int? { nil }
init?(stringValue: String) {
self.stringValue = stringValue
}
init?(intValue: Int) { return nil }
}
}
Имея это под рукой, вы можете расширить JSONDecoder
, чтобы получить более удобный сайт для звонков:
extension JSONDecoder {
func decode<T: Decodable>(nested: [T].Type, from data: Data) throws -> [T] {
try decode(Nester<T>.self, from: data).elements
}
}
Тогда остается просто вызвать новую перегрузку:
let places = try JSONDecoder().decode(nested: [Place].self, from: data)
P.S. при желании вы можете скрыть сложную структуру внутри расширения, в результате получится что-то вроде этого:
extension JSONDecoder {
func decode<T: Decodable>(nested: [T].Type, from data: Data) throws -> [T] {
try decode(Nester<T>.self, from: data).elements
}
private struct Nester<T: Decodable>: Decodable {
let elements: [T]
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let key = container.allKeys.first {
elements = try container.decode([T].self, forKey: key)
} else {
throw DecodingError.typeMismatch([String:Any].self, DecodingError.Context(codingPath: [], debugDescription: "Expected to find at least one key"))
}
}
struct CodingKeys: CodingKey {
let stringValue: String
var intValue: Int? { nil }
init?(stringValue: String) {
self.stringValue = stringValue
}
init?(intValue: Int) { return nil }
}
}
}
Обратной стороной является то, что вы не сможете повторно использовать структуру, если хотите расширить другие декодеры, кроме JSON.
person
Cristik
schedule
27.11.2020