Ожидалось декодирование Int, но вместо этого было найдено число

У меня возникла проблема с разбором JSON в Swift 4.2. Вот следующий код, который показал ошибку времени выполнения.

Мои данные Json следующие, которые я получил с сервера.

{
    code: 406,
    message: "Email Address already Exist.",
    status: 0
}

Я использую Codable для создания своей структуры следующим образом

struct Registration: Codable {
    var code: Int
    var status: Int
    private enum CodinggKeys: String, CodingKey {
        case code
        case status
    }
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        do {
            self.code = Int(try container.decode(String.self, forKey: .code))!
        } catch DecodingError.typeMismatch {
            let value = try container.decode(Double.self, forKey: .code)
            self.code = Int(value);
        }

        do {
            self.status = try container.decode(Int.self, forKey: .status)
        } catch DecodingError.typeMismatch {
            let value = try container.decode(String.self, forKey: .status)
            self.status = Int(value);
        }
    }
} 

Но каждый раз я получал ошибку при синтаксическом анализе ключа status.

Примечание. Я пытался анализировать статус в String, Int, Double, Decimal, NSInterger, но ни один из них не работает. каждый раз, когда я получаю ту же ошибку. Ожидалось декодирование UInt, но вместо этого было найдено число.


person Jatin Chauhan    schedule 27.10.2018    source источник
comment
остальные поля работают? Также у вас опечатка в названии перечисления CodingKey. CodinggKeys вместо CodingKeys. может в этом проблема? возможно, он берет другое перечисление из вашего проекта вместо того, которое вы только что объявили   -  person Catalina T.    schedule 27.10.2018
comment
Как вы тестируете свою модель? У меня работает на PlayGround.   -  person Glenn Posadas    schedule 27.10.2018
comment
pastebin.com/0UynM1wa Работает нормально..   -  person Brandon    schedule 27.10.2018
comment
Пожалуйста, покажите необработанный ответ сервера, а не вывод отладчика.   -  person Gereon    schedule 27.10.2018
comment
Добавьте полученный ответ JSON, чтобы мы могли отладить проблему. Если JSON, который вы добавили в вопрос, является правильным, здесь нет необходимости в init(from:). Codable может справиться с этим автоматически.   -  person PGDev    schedule 29.10.2018


Ответы (4)


Сообщение об ошибке вводит в заблуждение. Это происходит, когда JSON содержит логическое значение, а структура имеет свойство Int для соответствующего ключа.

Скорее всего, ваш JSON фактически выглядит так:

{
    "code": 406,
    "message": "Email Address already Exist.",
    "status": false
}

и соответственно ваша структура должна быть

struct Registration: Codable {
    let code: Int
    let status: Bool
}

if let registration = try? JSONDecoder().decode(Registration.self, from: data) {
    print(registration.code) // 406
    print(registration.status) // false
}
person Gereon    schedule 27.10.2018
comment
Я только что изменил ключ состояния на bool, и он отлично работает. Спасибо @Gereon - person Jatin Chauhan; 12.11.2018

Для таких проблем проверьте и убедитесь, что ответ и тип ответа, указанные в структуре, совпадают. Здесь кажется, что ваш ответ неверен. Статус может быть истинным или ложным

{
    code: 406,
    message: "Email Address already Exist.",
    status: 0
}

Если статус верен, измените свою структуру как,

struct Registration: Codable {
    var code: Int
    var status: Bool
    var message: String
}

если статус равен 0, измените var status: Bool на var status: Int в приведенной выше структуре.

person Varun P V    schedule 25.06.2020

Вам не нужно реализовывать собственный инициализатор декодирования, если свойства вашей структуры уже Decodable. Вам также не нужны пользовательские CodingKeys, как упоминал @Gereon.

Для следующих данных JSON:

let data = """
    {
        "code": 406,
        "message": "Email Address already Exist.",
        "status": 0
    }
    """.data(using: .utf8)!

Это отлично работает:

struct Registration: Codable {
    var code: Int
    var status: Int
}

if let registration = try? JSONDecoder().decode(Registration.self, from: data) {
    print(registration.code) // 406
    print(registration.status) // 0
}

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

person dnlggr    schedule 27.10.2018
comment
Зачем определять CodingKeys? Компилятор сделает это за вас. - person Gereon; 27.10.2018
comment
Верно конечно в данном случае, спасибо. Я обновил ответ. - person dnlggr; 27.10.2018

Я думаю, мы можем использовать это для решения таких вопросов:

protocol DecodingHelper {

    associatedtype Keys: CodingKey

    static func getStringValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> String

    static func getIntValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Int

    static func getBoolValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Bool
}

extension DecodingHelper {

    static func getStringValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> String {
        var str: String = ""

        if let obj = try? container.decode(String.self, forKey: key) {
            str = obj
        }
        else if let obj = try? container.decode(Int.self, forKey: key){
            str = String(obj)
        }
        return str
    }

    static func getIntValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Int {
        var val: Int = 0

        if let obj = try? container.decode(String.self, forKey: key),
            let intVal = Int(obj){
            val = intVal
        }
        else if let obj = try? container.decode(Int.self, forKey: key){
            val = obj
        }
        return val
    }

    static func getBoolValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Bool {
        var val: Bool = false

        if let obj = try? container.decode(String.self, forKey: key),
            let intVal = Int(obj){

            (intVal != 0) ? (val = true) : (val = false)
        }
        else if let obj = try? container.decode(Int.self, forKey: key){
            (obj != 0) ? (val = true) : (val = false)
        }
        else if let obj = try? container.decode(Bool.self, forKey: key){
            val = obj
        }
        return val
    }
}



struct VideoFeedback: Codable {

    // MARK:- Variables -

    var isFeedbackProvided:Bool = true

    // MARK:- Initialisation -

    private enum CodingKeys: String, DecodingHelper, CodingKey {

        typealias Keys = CodingKeys

        case isFeedbackProvided = "lastVideoFeedback"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)

        isFeedbackProvided = CodingKeys.getBoolValue(values, key: .isFeedbackProvided)
    }
}

Дайте мне знать, если у вас есть какие-либо предложения по улучшению этого.

person Mohd Haider    schedule 09.06.2020