swift 4 Codable - 如果有字符串或字典如何解码?

swift 4 Codable - how to decode if there is string or dictionary?

我有这样的结构:

struct OrderLine: Codable{
    let absUrl: String?
    let restApiUrl : String?
    let description : String?
    let quantity : Int?
    let subscription: Subs?
    let total: Double?
 }

struct Subs: Codable{
    let quantity: Int?
    let name: String?
}

并且一些 OrderLine 在服务器响应中有

"subscription": {
   "quantity": 6,
   "name": "3 Months"
},

但有时它有 String 类型:

"subscription": "",

没有 subscription 一切正常,但是我有一个错误

CodingKeys(stringValue: "subscription", intValue: nil)], 
   debugDescription: "Expected to decode Dictionary<String, Any> 
   but found a string/data instead.", underlyingError: nil)

所以我的问题是 - 如何解码或 String?"",或 Subs? 而没有任何错误? p.s。如果我只像 String? 一样解码它,则会出现错误 debugDescription: "Expected to decode String but found a dictionary instead.", underlyingError: nil)

您只需要自己实现 init(from:) 并尝试将 subscription 键的值解码为代表 SubsDictionaryString.

struct OrderLine: Codable {
    let absUrl: String?
    let restApiUrl : String?
    let description : String?
    let quantity : Int?
    let subscription: Subs?
    let total: Double?

    private enum CodingKeys: String, CodingKey {
        case absUrl, restApiUrl, description, quantity, subscription, total
    }

    init(from decoder:Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.absUrl = try container.decodeIfPresent(String.self, forKey: .absUrl)
        self.restApiUrl = try container.decodeIfPresent(String.self, forKey: .restApiUrl)
        self.description = try container.decodeIfPresent(String.self, forKey: .description)
        self.quantity = try container.decodeIfPresent(Int.self, forKey: .quantity)
        self.total = try container.decodeIfPresent(Double.self, forKey: .total)
        if (try? container.decodeIfPresent(String.self, forKey: .subscription)) == nil {
            self.subscription = try container.decodeIfPresent(Subs.self, forKey: .subscription)
        } else {
            self.subscription = nil
        }
    }
}