Использование Decodable с наследованием вызывает исключение

Я работаю с сервисом Rest API, где ответы делятся на базовый ответ, и все остальные ответы наследуются от него.

Я пытаюсь создать такую ​​же структуру для своих классов моделей ответов, используя интерфейс Decoder.

Однако у меня проблемы с декодированием унаследованного класса.

Я попытался решить эту проблему: Использование Decodable в Swift 4 с наследованием

Но без везения.

Это начальная структура:

class LoginResponse: BaseResponse{

    var Message: String?

    private enum CodingKeys: String, CodingKey{
        case Message
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        Message = try container.decode(String.self, forKey: .Message)
        let superDecoder = try container.superDecoder()
        try super.init(from: superDecoder)
    }
}

class BaseResponse: Decodable {

    var Status: Int?

    private enum CodingKeys: String, CodingKey{
        case Status
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self) // This line throws the exception
        Status = try container.decode(Int.self, forKey: .Status)
    }
}

Вот как я пытаюсь расшифровать:

 let decoder = JSONDecoder()
 let json = "{\"Message\":\"saa\",\"Status\":200}"
 let login = try! decoder.decode(LoginResponse.self, from: json.data(using: .utf8)!)

Как я писал выше, эта строка выдает исключение (в классе BaseResponse)

let container = try decoder.container(keyedBy: CodingKeys.self)


Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.valueNotFound(Swift.KeyedDecodingContainer<SampleProject.BaseResponse.(CodingKeys in _084835F8074C7E8C5E442FE2163A7A00)>, Swift.DecodingError.Context(codingPath: [Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "super", intValue: nil)], debugDescription: "Cannot get keyed decoding container -- found null value instead.", underlyingError: nil))

Не знаю, как с этим бороться.

Заранее спасибо!


person dor506    schedule 19.12.2017    source источник


Ответы (1)


Нет необходимости использовать superDecoder, вы можете просто сделать это (я изменил имена переменных на строчные, чтобы соответствовать соглашению об именах)

class LoginResponse: BaseResponse {

    let message: String

    private enum CodingKeys: String, CodingKey{
        case message = "Message"
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        message = try container.decode(String.self, forKey: .message)
        try super.init(from: decoder)
    }
}

class BaseResponse: Decodable {

    let status: Int

    private enum CodingKeys: String, CodingKey{
        case status = "Status"
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        status = try container.decode(Int.self, forKey: .status)
    }
}
  • decoder.decode(BaseResponse.self ... декодирует только status
  • decoder.decode(LoginResponse.self ... декодирует status и message

И никогда не кодируйте/декодируйте с помощью try!. Обработать ошибку.

person vadian    schedule 19.12.2017
comment
Спасибо! это работает!. Можете ли вы уточнить, пожалуйста? чем это отличается от аналогичной ссылки, которую я разместил - person dor506; 19.12.2017
comment
Я сомневаюсь, что данная структура JSON в видео WWDC такая же, как в вашем вопросе. Тем не менее я могу подтвердить, что superDecoder действительно выдает ошибку. - person vadian; 19.12.2017
comment
я делаю это, но это вызывает исключение, когда я пытаюсь получить значение дочернего класса (как LoginResponse), но нет проблем в super (как BaseResponse), я много ищу, но отладка не показывает описание исключения - person Ahmad Labeeb; 25.02.2018
comment
@vadian Спасибо! Мне потребовались часы, чтобы наконец найти ваше решение, я ценю это. - person amir jam; 17.07.2020