Skip to content

Instantly share code, notes, and snippets.

@gromwel
Last active December 8, 2022 12:19
Show Gist options
  • Save gromwel/bb8384b9d5462cce52112ac38498de71 to your computer and use it in GitHub Desktop.
Save gromwel/bb8384b9d5462cce52112ac38498de71 to your computer and use it in GitHub Desktop.
Decoding and encoding JSON with dynamic keys.
import Foundation
struct Film: Codable {
let actor: String
let year: Int
let key: String
// Объявляем ключи только для тех которые внутри модели
enum CodingKeys: CodingKey {
case actor
case year
}
// Инициализация
init(actor: String, year: Int, key: String) {
self.actor = actor
self.year = year
self.key = key
}
// Декодируем
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
// Пробуем получить ключ
guard let key = container.codingPath.first?.stringValue else {
throw NSError(domain: "Key not found", code: 0, userInfo: nil)
}
// Свойства модели
self.actor = try container.decode(String.self, forKey: .actor)
self.year = try container.decode(Int.self, forKey: .year)
self.key = key
}
// Кодируем
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
// Кодируем только свойства модели
try container.encode(self.actor, forKey: .actor)
try container.encode(self.year, forKey: .year)
}
}
struct Films: Codable {
let array: [Film]
// Инициализация
init(_ array: [Film]) {
self.array = array
}
// Динамические ключи
private struct DynamicKeys: CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) { nil }
}
// Декодируем
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: DynamicKeys.self)
// Перебираем все ключи контейнера
var persons: [Film] = []
for key in container.allKeys {
// Создаем динамический ключ
if let dynamicKey = DynamicKeys(stringValue: key.stringValue) {
// Пробуем получить модель по ключу
let person = try container.decode(Film.self, forKey: dynamicKey)
persons.append(person)
}
}
self.array = persons
}
// Кодируем
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: DynamicKeys.self)
// Перебираем модели
for person in self.array {
// Создаем динамический ключ
if let key = DynamicKeys(stringValue: person.key) {
// Пробуем закодировать модель
try container.encode(person, forKey: key)
}
}
}
}
// Декодирование
let json =
"""
{
"Die Another Day": {
"actor": "Pierce Brosnan",
"year": 2002
},
"No Time to Die": {
"actor": "Daniel Craig",
"year": 2021
}
}
"""
if let data = json.data(using: .utf8) {
do {
let model = try JSONDecoder().decode(Films.self, from: data)
model.array.forEach { print($0) }
} catch {
print(error)
}
}
// Кодирование
var persons = Films([
Film(actor: "Daniel Craig", year: 2006, key: "Casino Royale"),
Film(actor: "Pierce Brosnan", year: 1995, key: "GoldenEye")
])
do {
let data = try JSONEncoder().encode(persons)
if let string = String(data: data, encoding: .utf8) {
print(string)
}
} catch {
print(error)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment