使用Codable在一个模型类中解码两个不同的JSON响应

使用Codable在一个模型类中解码两个不同的JSON响应,json,swift,decodable,Json,Swift,Decodable,基于这个需求,我从api得到了两种不同的响应。就是 { "shopname":"xxx", "quantity":4, "id":1, "price":200.00, } 另一个反应 { "storename":"xxx", "qty":4, "id":1, "amount":200.00, } 这里两个json值在同一个模型类中解码。请帮助我解决这个问题 是否可以在单个变量中设置值,如qty和QUOTE,这两个变量都存储在基于键参数可用性的同一个变量中使用l

基于这个需求,我从api得到了两种不同的响应。就是

{
  "shopname":"xxx",
  "quantity":4,
  "id":1,
  "price":200.00,
}
另一个反应

{
  "storename":"xxx",
  "qty":4,
  "id":1,
  "amount":200.00,
}
这里两个json值在同一个模型类中解码。请帮助我解决这个问题

是否可以在单个变量中设置值,如qty和QUOTE,这两个变量都存储在基于键参数可用性的同一个变量中

使用like

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


}

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


}

这里有一种方法可以让您的代码中只有一个属性,而不是两个选项:

定义一个结构,其中包含您需要的所有属性,以及您希望在代码中使用的名称。然后,定义两个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)
}

这里有一种方法可以让您的代码中只有一个属性,而不是两个选项:

定义一个结构,其中包含您需要的所有属性,以及您希望在代码中使用的名称。然后,定义两个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)
}
在单个模型中处理不同的键名

下面是两个示例jsondictionaries,它们有一些公共键,一个、两个和几个不同的键,它们的错误用途相同

示例json:

let error_json:[String: Any] = [
    "error_code": 404,                  //different
    "error_message": "file not found",  //different
    "one":1, //common
    "two":2  //common
]
let failure_json:[String: Any] = [
    "failure_code": 404,                 //different
    "failure_message": "file not found", //different
    "one":1, //common
    "two":2  //common
]
通用模型

struct CommonModel : Decodable {
    var code: Int?
    var message: String?
    var one:Int  //common
    var two:Int? //common
    
    private enum CodingKeys: String, CodingKey{ //common
        case one, two
    }
    private enum Error_CodingKeys : String, CodingKey {
        case  code = "error_code", message = "error_message"
    }
    private enum Failure_CodingKeys : String, CodingKey {
        case  code = "failure_code", message = "failure_message"
    }
    init(from decoder: Decoder) throws {
        let commonValues =  try decoder.container(keyedBy: CodingKeys.self)
        let errors = try decoder.container(keyedBy: Error_CodingKeys.self)
        let failures = try decoder.container(keyedBy: Failure_CodingKeys.self)
        
        ///common
        self.one = try commonValues.decodeIfPresent(Int.self, forKey: .one)!
        self.two = try commonValues.decodeIfPresent(Int.self, forKey: .two)
        /// different
        if errors.allKeys.count > 0{
            self.code = try errors.decodeIfPresent(Int.self, forKey: .code)
            self.message = try errors.decodeIfPresent(String.self, forKey: .message)
        }
        if failures.allKeys.count > 0{
            self.code = try failures.decodeIfPresent(Int.self, forKey: .code)
            self.message = try failures.decodeIfPresent(String.self, forKey: .message)
        }
    }
}
下面的扩展将帮助您将字典转换为数据

public extension Decodable {
    init(from: Any) throws {
        let data = try JSONSerialization.data(withJSONObject: from, options: .prettyPrinted)
        let decoder = JSONDecoder()
        self = try decoder.decode(Self.self, from: data)
    }
}
测试

public func Test_codeble(){
    do {
         let err_obj = try CommonModel(from: error_json)
         print(err_obj)
         let failed_obj = try CommonModel(from: failure_json)
         print(failed_obj)
        
    }catch let error {
        print(error.localizedDescription)
    }
}
在单个模型中处理不同的键名

下面是两个示例jsondictionaries,它们有一些公共键,一个、两个和几个不同的键,它们的错误用途相同

示例json:

let error_json:[String: Any] = [
    "error_code": 404,                  //different
    "error_message": "file not found",  //different
    "one":1, //common
    "two":2  //common
]
let failure_json:[String: Any] = [
    "failure_code": 404,                 //different
    "failure_message": "file not found", //different
    "one":1, //common
    "two":2  //common
]
通用模型

struct CommonModel : Decodable {
    var code: Int?
    var message: String?
    var one:Int  //common
    var two:Int? //common
    
    private enum CodingKeys: String, CodingKey{ //common
        case one, two
    }
    private enum Error_CodingKeys : String, CodingKey {
        case  code = "error_code", message = "error_message"
    }
    private enum Failure_CodingKeys : String, CodingKey {
        case  code = "failure_code", message = "failure_message"
    }
    init(from decoder: Decoder) throws {
        let commonValues =  try decoder.container(keyedBy: CodingKeys.self)
        let errors = try decoder.container(keyedBy: Error_CodingKeys.self)
        let failures = try decoder.container(keyedBy: Failure_CodingKeys.self)
        
        ///common
        self.one = try commonValues.decodeIfPresent(Int.self, forKey: .one)!
        self.two = try commonValues.decodeIfPresent(Int.self, forKey: .two)
        /// different
        if errors.allKeys.count > 0{
            self.code = try errors.decodeIfPresent(Int.self, forKey: .code)
            self.message = try errors.decodeIfPresent(String.self, forKey: .message)
        }
        if failures.allKeys.count > 0{
            self.code = try failures.decodeIfPresent(Int.self, forKey: .code)
            self.message = try failures.decodeIfPresent(String.self, forKey: .message)
        }
    }
}
下面的扩展将帮助您将字典转换为数据

public extension Decodable {
    init(from: Any) throws {
        let data = try JSONSerialization.data(withJSONObject: from, options: .prettyPrinted)
        let decoder = JSONDecoder()
        self = try decoder.decode(Self.self, from: data)
    }
}
测试

public func Test_codeble(){
    do {
         let err_obj = try CommonModel(from: error_json)
         print(err_obj)
         let failed_obj = try CommonModel(from: failure_json)
         print(failed_obj)
        
    }catch let error {
        print(error.localizedDescription)
    }
}

在一个模型类中添加两个json响应,如josn{shopname:xxx,数量:4,id:1,价格:200.00,storename:xxx,数量:4,金额:200.00,},然后创建模型类在一个模型类中添加两个json响应,如josn{shopname:xxx,数量:4,id:1,价格:200.00,storename:xxx,数量:4,金额:200.00,}然后创建模型ClassThank@vikash。。是否可以在单个变量中设置值。与quantity和quantity一样,它们都基于可用性存储在同一个变量中感谢@vikash。。是否可以在单个变量中设置值。与quantity和quantity一样,它们基于可用性存储在同一个变量中。您不应使用数据作为模型名称。这已经是一个基础类型了。更新了我的答案。让json1={shopname:xxx,数量:4,id:1,价格:200.00,}。数据使用:.utf8!让json2={storename:xxx,qty:4,id:1,amount:200.00,}.datausing:.utf8!这里需要传递我的json响应??请分享一些有用的url,以了解更多关于我关注的问题。这只是一个示例,您可以在操场上尝试代码。在代码中,您将使用JSON响应数据代替我的json1或json2@Gereon谢谢,您不应该使用数据作为模型名称。这已经是一个基础类型了。更新了我的答案。让json1={shopname:xxx,数量:4,id:1,价格:200.00,}。数据使用:.utf8!让json2={storename:xxx,qty:4,id:1,amount:200.00,}.datausing:.utf8!这里需要传递我的json响应??请分享一些有用的url,以了解更多关于我关注的问题。这只是一个示例,您可以在操场上尝试代码。在代码中,您将使用JSON响应数据代替我的json1或json2@Gereon谢谢