使用 Codable 用一个结构解码两个不同的 JSON 响应

Nev*_*ani 5 json struct swift swift4 codable

我从两个不同的端点获取数据。一个端点返回这样的订单:

{
  "price":"123.49",
  "quantity":"4",
  "id":"fkuw-4834-njk3-4444",
  "highPrice":"200",
  "lowPrice":"100"
}
Run Code Online (Sandbox Code Playgroud)

另一个端点返回这样的顺序:

{
  "p":"123.49", //price 
  "q":"4", //quantity
  "i":"fkuw-4834-njk3-4444" //id
}
Run Code Online (Sandbox Code Playgroud)

我想使用相同的 Codable 结构来解码两个 JSON 响应。我该怎么做?是否可以使用一个结构来做到这一点,或者我必须创建第二个结构?这是第一个 JSON 返回的结构现在的样子:

struct SimpleOrder:Codable{
    var orderPrice:String
    var orderQuantity:String
    var id:String
    var highPrice:String

    private enum CodingKeys: String, CodingKey {
        case orderPrice = "price"
        case orderQuantity = "quantity"
        case id
        case highPrice
    }
}
Run Code Online (Sandbox Code Playgroud)

vad*_*ian 5

您可以这样做,但您必须将所有属性声明为可选并编写自定义初始值设定项

struct SimpleOrder : Decodable {
    var orderPrice : String?
    var orderQuantity : String?
    var id : String?
    var highPrice : String?

    private enum CodingKeys: String, CodingKey {
        case orderPrice = "price"
        case orderQuantity = "quantity"
        case id
        case highPrice
        case i, q, p
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        orderPrice = try container.decodeIfPresent(String.self, forKey: .orderPrice)
        orderPrice = try container.decodeIfPresent(String.self, forKey: .p)
        orderQuantity = try container.decodeIfPresent(String.self, forKey: .orderQuantity)
        orderQuantity = try container.decodeIfPresent(String.self, forKey: .q)
        id = try container.decodeIfPresent(String.self, forKey: .id)
        id = try container.decodeIfPresent(String.self, forKey: .i)
        highPrice = try container.decodeIfPresent(String.self, forKey: .highPrice)
    }
}
Run Code Online (Sandbox Code Playgroud)

或者使用两个不同的键集,检查其中一个键的出现并选择合适的键集。好处是pricequantity并且id可以声明为非可选

struct SimpleOrder : Decodable {
    var orderPrice : String
    var orderQuantity : String
    var id : String
    var highPrice : String?

    private enum CodingKeys: String, CodingKey {
        case orderPrice = "price"
        case orderQuantity = "quantity"
        case id
        case highPrice
    }

    private enum AbbrevKeys: String, CodingKey {
        case i, q, p
    }

    init(from decoder: Decoder) throws {
        let cContainer = try decoder.container(keyedBy: CodingKeys.self)
        if let price = try cContainer.decodeIfPresent(String.self, forKey: .orderPrice) {
            orderPrice = price
            orderQuantity = try cContainer.decode(String.self, forKey: .orderQuantity)
            id = try cContainer.decode(String.self, forKey: .id)
            highPrice = try cContainer.decode(String.self, forKey: .highPrice)
        } else {
            let aContainer = try decoder.container(keyedBy: AbbrevKeys.self)
            orderPrice = try aContainer.decode(String.self, forKey: .p)
            orderQuantity = try aContainer.decode(String.self, forKey: .q)
            id = try aContainer.decode(String.self, forKey: .i)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)