Swift 4 Codable — логические или строковые значения

Ищу информацию о том, как бы вы справились со сценарием, с которым я недавно столкнулся.

Я успешно использовал Swift 4s Codable, но сегодня заметил неожиданный сбой. API, с которым я работаю, говорит, что возвращает boolean для ключа manage_stock.

Моя заглушенная структура выглядит так:

struct Product: Codable {
    var manage_stock: Bool?
}

Это работает нормально, проблема в том, что API иногда возвращает string вместо boolean.

Из-за этого мой декод не работает с:

Expected to decode Bool but found a string/data instead.

Строка всегда равна "parent", и я хочу, чтобы она равнялась false.

Я также не против изменить свою структуру на var manage_stock: String?, если это упростит получение данных JSON из API. Но, конечно, если я изменю это, моя ошибка изменится на:

Expected to decode String but found a number instead.

Есть ли простой способ справиться с этой мутацией, или мне придется отказаться от всей автоматизации, которую Codable привносит в таблицу, и реализовать свою собственную init(decoder: Decoder).

Ваше здоровье


person mg87    schedule 05.02.2018    source источник
comment
Вы должны реализовать мой собственный init(decoder: Decoder). Или попросите владельца API отправить согласованные данные ????   -  person vadian    schedule 05.02.2018
comment
вообще говоря, такой хаотичный API должен исправляться внутри API, а не исправлять клиентов API, потому что вы не можете исправлять свое приложение для каждой глупой аномалии, допущенной веб-разработчиками; поэтому они (API и его разработчики) должны придерживаться строгих (необязательно необязательных) типов; Вы могли бы договориться с ними вместо того, чтобы пытаться прикрыть их дерьмо? потому что такая проблема должна решаться на уровне API, а не на уровне приложения.   -  person holex    schedule 05.02.2018
comment
может быть связано/полезно: stackoverflow.com/questions/48297263/   -  person Scriptable    schedule 05.02.2018


Ответы (1)


Поскольку вы не всегда можете контролировать API, с которыми работаете, вот один простой способ решить эту проблему с помощью Codable напрямую, переопределив init(from:):

struct Product : Decodable {
    // Properties in Swift are camelCased. You can provide the key separately from the property.
    var manageStock: Bool?

    private enum CodingKeys : String, CodingKey {
        case manageStock = "manage_stock"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        do {
            self.manageStock = try container.decodeIfPresent(Bool.self, forKey: .manageStock)
        } catch DecodingError.typeMismatch {
            // There was something for the "manage_stock" key, but it wasn't a boolean value. Try a string.
            if let string = try container.decodeIfPresent(String.self, forKey: .manageStock) {
                // Can check for "parent" specifically if you want.
                self.manageStock = false
            }
        }
    }
}

Дополнительную информацию об этом см. в разделе Кодирование и декодирование пользовательских типов.

person Itai Ferber    schedule 05.02.2018
comment
Вот что я подумал, я приму это, поскольку вы привели хороший пример. Ваше здоровье. - person mg87; 07.02.2018
comment
отличное решение, дружище! Большое спасибо! - person oskarko; 18.03.2021