-
-
Save michaelevensen/379320bfa4e2d8a89311df13ee739d09 to your computer and use it in GitHub Desktop.
Decoding and encoding JSON with dynamic keys.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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