Swift 从兼容的可解码器 class 派生的 class 可解码器失败(JSONDecoder 用于解码)
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"
}
}
没有正确解码。 cards 和 activeCardId 保持为零。当我将 public class CardListResponse: BaseResponse 更改为 public class CardListResponse: Decodable the cards 和 activeCardId 解析得很好(但显然我没有从 base class).
我该如何应对?
如果问题不清楚这里的示例 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)
}
}
你需要在 subclass 中实现 init(from decoder: Decoder)
并调用 superclass 初始化,尽管你不需要为 superclass[ 实现它=16=]
init for CardListResponse
,注意对 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)
}
另一种选择是完全跳过继承并改用组合。在 subclass 中,你为 CodeAndDetails
数组创建了一个 属性,这样你就不再需要特殊的 init
方法了。
然后可以将 CardListResponse 更改为以下,并且可以删除超级 class。在长运行中我认为这是一个比较有吸引力的解决方案。
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"
}
}
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"
}
}
没有正确解码。 cards 和 activeCardId 保持为零。当我将 public class CardListResponse: BaseResponse 更改为 public class CardListResponse: Decodable the cards 和 activeCardId 解析得很好(但显然我没有从 base class).
我该如何应对?
如果问题不清楚这里的示例 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)
}
}
你需要在 subclass 中实现 init(from decoder: Decoder)
并调用 superclass 初始化,尽管你不需要为 superclass[ 实现它=16=]
init for CardListResponse
,注意对 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)
}
另一种选择是完全跳过继承并改用组合。在 subclass 中,你为 CodeAndDetails
数组创建了一个 属性,这样你就不再需要特殊的 init
方法了。
CardListResponse 更改为以下,并且可以删除超级 class。在长运行中我认为这是一个比较有吸引力的解决方案。
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"
}
}