对于从可解码兼容类派生的类(JSONDecoder 用于解码),Swift Decodable 失败 [英] Swift Decodable fails for a class derived from a decodable compliant class (JSONDecoder is used for decoding)
问题描述
public struct CodeAndDetails: Codable {
public let html: String
public var code: String
private enum CodingKeys: String, CodingKey {
case html = "DETAILS", code = "CODE"
}
public func getMessage(font: UIFont) -> NSAttributedString? {
let res = NSAttributedString(html: html, font: font)
return res
}
}
public class BaseResponse: Decodable {
enum CodingKeys: String, CodingKey {
case successDetails = "Success"
}
public let successDetails: [CodeAndDetails]
}
这里:
public class CardListResponse: BaseResponse {
public var cards: [DebitCard]?
public var activeCardId: Int?
enum CodingKeys: String, CodingKey {
case cards = "row"
case activeCardId = "CurrentActiveId"
}
}
未正确解码.卡和 activeCardId 保持为零.当我将公共类 CardListResponse: BaseResponse 更改为公共类 CardListResponse: 可解码卡片和 activeCardId 解析就好了(但显然我没有从基类中获得有效负载).
Does not decode properly. cards and activeCardId stay nil. When I change public class CardListResponse: BaseResponse to public class CardListResponse: Decodable the cards and activeCardId parse just fine (but obviously I get no payload from base class).
我该如何应对?
如果从这里的示例 json 的问题中不清楚:
In case it's not clear from the question here's sample json:
我的 JSON
{
"row":[
{
"PicPath":"MC"
},
{
"IsDefault":"",
"PicPath":"VISA"
}
],
"CurrentActiveId":17504322,
"Success":[
{
"DETAILS":"\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u043e",
"CODE":"1"
}
]
}
public struct DebitCard: Decodable
{
public let accountContractId: Int?
public let last8: String?
public let balanceString: String?
public let currName: String?
public let iCardId: Int?
public let isMain: Bool?
public let cardNameWithCurrencyCode: String?
public let card4: String?
public let title: String?
public let picPath: String?
enum CodingKeys: String, CodingKey {
case accountContractId = "AcntContractId"
case expire = "Expire"
case last8 = "Card8"
case balanceString = "Balance"
case currName = "CurrName"
case iCardId
case isMainString = "isMain"
case cardNameWithCurrencyCode = "CardName"
case card4 = "Card4"
case title = "CrdTInfo"
case picPath = "PicPath"
}
public init(from decoder: Decoder) throws
{
let values = try decoder.container(keyedBy: CodingKeys.self)
accountContractId = try values.decode(Int.self, forKey: .accountContractId)
last8 = try values.decode(String.self, forKey: .last8)
balanceString = try values.decode(String.self, forKey: .balanceString)
currName = try values.decode(String.self, forKey: .currName)
iCardId = try values.decode(Int.self, forKey: .iCardId)
let isMainString = try values.decode(String.self, forKey: .isMainString)
isMain = isMainString.toBool
cardNameWithCurrencyCode = try values.decode(String.self, forKey: .cardNameWithCurrencyCode)
card4 = try values.decode(String.self, forKey: .card4)
title = try values.decode(String.self, forKey: .title)
picPath = try values.decode(String.self, forKey: .picPath)
}
}
推荐答案
你需要在子类中实现 init(fromdecoder: Decoder)
并调用超类 init 虽然你不需要为超类实现它
You need to implement init(from decoder: Decoder)
in the subclass and call the superclass init although you don't need to implement it for the superclass
init for CardListResponse
,注意调用 super.init
init for CardListResponse
, notice the call to super.init
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
cards = try container.decode([DebitCard].self, forKey: .cards)
activeCardId = try container.decode(Int.self, forKey: .activeCardId)
try super.init(from: decoder)
}
<小时>
另一种选择是完全跳过继承并使用组合代替.在子类中,您为 CodeAndDetails
数组创建了一个属性,这样您就不再需要特殊的 init
方法.
Another option is to skip inheritance altogether and use composition instead. In the subclass you make a property for the CodeAndDetails
array instead, this way you won't need a special init
method anymore.
CardListResponse 然后可以更改为下面,并且可以删除超类.从长远来看,我认为这是一个更有吸引力的解决方案.
CardListResponse can then be changed to below and the super class can be removed. In the long run I think this is a more attractive solution.
public class CardListResponse: Decodable {
public var cards: [DebitCard]?
public var activeCardId: Int?
public var details: [CodeAndDetails]
private enum CodingKeys: String, CodingKey {
case cards = "row"
case activeCardId = "CurrentActiveId"
case details = "Success"
}
}
这篇关于对于从可解码兼容类派生的类(JSONDecoder 用于解码),Swift Decodable 失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!