Декодирование двух разных ответов JSON в одном классе модели с использованием Codable - PullRequest
0 голосов
/ 15 ноября 2018

Исходя из требования, я получил два разных ответа от API.То есть

{
  "shopname":"xxx",
  "quantity":4,
  "id":1,
  "price":200.00,
}

другой ответ

{
  "storename":"xxx",
  "qty":4,
  "id":1,
  "amount":200.00,
}

Здесь оба значения json декодируются в одном классе модели.Пожалуйста, помогите мне решить эту проблему.

, если возможно установить значение в одной переменной, например Кол-во и количество , оба хранятся в одной переменной в зависимости от доступности ключевого параметра

Ответы [ 2 ]

0 голосов
/ 15 ноября 2018

Вот подход, который позволяет вам иметь только одно свойство в вашем коде вместо двух необязательных:

Определить структуру, которая содержит все необходимые вам свойства, с именами, которые вы хотели бы использовать вваш код.Затем определите два перечисления CodingKey, которые сопоставляют эти свойства двум разным форматам JSON и реализуют пользовательский инициализатор:

let json1 = """
{
    "shopname":"xxx",
    "quantity":4,
    "id":1,
    "price":200.00,
}
""".data(using: .utf8)!

let json2 = """
{
    "storename":"xxx",
    "qty":4,
    "id":1,
    "amount":200.00,
}
""".data(using: .utf8)!

struct DecodingError: Error {}

struct Model: Decodable {
    let storename: String
    let quantity: Int
    let id: Int
    let price: Double

    enum CodingKeys1: String, CodingKey {
        case storename = "shopname"
        case quantity
        case id
        case price
    }

    enum CodingKeys2: String, CodingKey {
        case storename
        case quantity = "qty"
        case id
        case price = "amount"
    }

    init(from decoder: Decoder) throws {
        let container1 = try decoder.container(keyedBy: CodingKeys1.self)
        let container2 = try decoder.container(keyedBy: CodingKeys2.self)

        if let storename = try container1.decodeIfPresent(String.self, forKey: CodingKeys1.storename) {
            self.storename = storename
            self.quantity = try container1.decode(Int.self, forKey: CodingKeys1.quantity)
            self.id = try container1.decode(Int.self, forKey: CodingKeys1.id)
            self.price = try container1.decode(Double.self, forKey: CodingKeys1.price)
        } else if let storename = try container2.decodeIfPresent(String.self, forKey: CodingKeys2.storename) {
            self.storename = storename
            self.quantity = try container2.decode(Int.self, forKey: CodingKeys2.quantity)
            self.id = try container2.decode(Int.self, forKey: CodingKeys2.id)
            self.price = try container2.decode(Double.self, forKey: CodingKeys2.price)
        } else {
            throw DecodingError()
        }
    }
}


do {
    let j1 = try JSONDecoder().decode(Model.self, from: json1)
    print(j1)
    let j2 = try JSONDecoder().decode(Model.self, from: json2)
    print(j2)
} catch {
    print(error)
}
0 голосов
/ 15 ноября 2018

Используйте как

struct modelClass : Codable {

    let amount : Float?
    let id : Int?
    let price : Float?
    let qty : Int?
    let quantity : Int?
    let shopname : String?
    let storename : String?


    enum CodingKeys: String, CodingKey {
        case amount = "amount"
        case id = "id"
        case price = "price"
        case qty = "qty"
        case quantity = "quantity"
        case shopname = "shopname"
        case storename = "storename"
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        amount = try values.decodeIfPresent(Float.self, forKey: .amount)
        id = try values.decodeIfPresent(Int.self, forKey: .id)
        price = try values.decodeIfPresent(Float.self, forKey: .price)
        qty = try values.decodeIfPresent(Int.self, forKey: .qty)
        quantity = try values.decodeIfPresent(Int.self, forKey: .quantity)
        shopname = try values.decodeIfPresent(String.self, forKey: .shopname)
        storename = try values.decodeIfPresent(String.self, forKey: .storename)
    }


}
...