Swift Codable декодирует изменение JSON и игнорирует некоторые поля

У меня есть 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 есть много вещей, но в основном это слишком запутанно для меня, и я не смог найти полезных примеров для своей проблемы.

Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
6
0
3 541
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Прежде всего никогда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, чтобы все заработало, прежде чем включать их в проект, и, очевидно, пропустил запятую вместо опечатки двоеточия. Еще раз спасибо. :)

Matej P 29.05.2019 10:25

Другие вопросы по теме