У меня есть REST API
, который возвращает JSON
. Этот API используется более чем одним сервисом (мобильным, веб-сайтом и т. д.), и он возвращает JSON
, внутри которого больше полей, чем мне нужно, и некоторые из этих дополнительных полей можно менять еженедельно.
Например, у меня есть JSON:
{ "name": "Toyota Prius", "horsepower": 134, "mileage": 123241, "manufactured": 2017, "location": "One city", "origin": "Japan",
"convert": true //more properties follows... }
В мобильном приложении мне нужно было бы расшифровать только поля: название, мощность и дату производства, остальное можно не учитывать. Также некоторые поля, такие как происхождение, раньше не существовали, но были добавлены несколько дней назад.
Вопрос в том, как написать пуленепробиваемый декодер, который не сломается, если в JSON
будут какие-то изменения, которые не повлияют на мою модель в приложении? Также у меня нет слов в выводе JSON
с сервера, и я не могу на это повлиять. Я просто получаю данные, и мне приходится работать с тем, что я получаю.
Я написал экспериментальный код для детской площадки (машина не распечатывается):
import UIKit
struct Car: Codable
{
let name: String
let horsePower: Int
let selected: Bool //this is used as additional property inside my app to mark selected cars
let index: Int //this is used as additional property inside my app for some indexing purposes
enum CodingKeys: String, CodingKey
{
case name
case horsePower = "horsepower"
case selected
case index
}
init(from decoder: Decoder) throws
{
let values = try decoder.container(keyedBy: CodingKeys.self)
selected = false
index = 0
name = try values.decode(String.self, forKey: .name)
horsePower = try values.decode(Int.self, forKey: .horsePower)
}
}
let json = "{\"name\": \"Toyota Prius\",\"horsepower\": 134, \"convert\", true}"
let data = json.data(using: .utf8)
if let car = try? JSONDecoder().decode(Car.self, from: data!)
{
//does not print... :(
print(car)
}
Я хотел бы напечатать автомобиль в моем примере, но в основном у меня есть рабочий код подтверждения, который не сломается, если JSON
изменить.
Также есть ли способ как-то получить описание ошибки декодирования?
Я знаю, что в документации Apple есть много вещей, но в основном это слишком запутанно для меня, и я не смог найти полезных примеров для своей проблемы.
Прежде всего никогдаtry? JSONDecoder...
, catch
всегда ошибка и распечатайте ее. Ошибки декодирования чрезвычайно описательны. Они говорят вам точно, что не так и даже где.
В вашем примере вы получите
"The given data was not valid JSON. ... No value for key in object around character 52."
что является неправильной запятой (вместо двоеточия) после convert\"
Чтобы декодировать только определенные ключи, объявите CodingKeys
соответствующим образом и удалите метод init
. selected
и index
, скорее всего, должны быть изменяемыми, поэтому объявите их как переменную со значением по умолчанию.
Если серверная часть изменит структуру JSON, вы получите сообщение об ошибке. Процесс декодирования в любом случае прервется независимо от API парсинга.
struct Car: Codable
{
let name: String
let horsePower: Int
let convert : Bool
var selected = false
var index = 0
enum CodingKeys: String, CodingKey {
case name, horsePower = "horsepower", convert
}
}
let json = """
{"name":"Toyota Prius","horsepower":134,"convert":true}
"""
let data = Data(json.utf8)
do {
let car = try JSONDecoder().decode(Car.self, from: data)
print(car)
} catch { print(error) }
Извините за поздний ответ, но ваше решение решило мои проблемы. Я играл в playgorund, чтобы все заработало, прежде чем включать их в проект, и, очевидно, пропустил запятую вместо опечатки двоеточия. Еще раз спасибо. :)