迅速可解码失败,用于从解码的兼容类派生的类(JSONDecoder用于解码)(Swift Decod

2019-10-29 12:37发布

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解析就好了(但显然我没有得到任何来自基类有效载荷)。

我怎么能应对这一切?

如果它不是清楚的问题这里的样品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)
    }
}

Answer 1:

您需要实现init(from decoder: Decoder)的子类,并调用父类的初始化,虽然你并不需要实现它的超

初始化为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)
}

另一种选择是完全跳过继承和使用组合物来代替。 在子类中你做了一个属性CodeAndDetails阵列代替,这样你就不会需要一个特殊init方法了。

CardListResponse然后可以如下改变和超类可以被删除。 从长远来看,我认为这是一个更具吸引力的解决方案。

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"
    }
}


文章来源: Swift Decodable fails for a class derived from a decodable compliant class (JSONDecoder is used for decoding)