我正在尝试使用Codable协议解析JSON,但出现异常。此异常是由于响应为null值而导致第二个响应为哪个nestedkeyedcontainer。
对于下面的json响应,它可以正常工作
let jsonStr = """
{
"response": {
"PURCHASE_FREE_SIM_RESPONSE": {
"TOPUP": null,
"TOTAL_PAYMENT_AMOUNT": "0",
"TRANSACTION_ID": "MFST0000233010",
"TAX": null,
"VAT": null,
"SHIPPING_AMOUNT": null,
"ITG_TRANSACTION_ID": "ITG000000138832750",
"CHANNEL_TRANSACTION_ID": "8e56ecf01b",
"PAYMENT_RESPONSE": null,
"APM_RESPONSE": null,
"APPLICATION_TYPE": null,
"NAME_OR_PAGE_ID": null,
"URL": null,
"CUSTOM_FIELD_1": null,
"CUSTOM_FIELD_2": null,
"CUSTOM_FIELD_3": null,
"FEE": null
}
},
"API-Code": "engbr_mvnepurchasefreesim",
"statuscode": 200,
"statusMessage": "SUCCESS",
"respCode": {
"ERROR_CODE": "0",
"ERROR_DESC": "Success"
}
}
"""
//=========Second Response===============
let jsonStr = """
{
**"response": null,**
"API-Code": null,
"statuscode": 500,
"statusMessage": "Undefined index: HOUSE_NO",
**"respCode": null**
}
"""
我的模特看起来像:-
struct SimPurResponse:Decodable{
let topUp:String
let totalPaymentAmt:String
let transId:String
let tax:String
let vat:String
let shipingAmt:String
let itgTransId:String
let chanelTransId:String
let paymentResponse:String
let apmResponse:String
let applicationType:String
let nameorPageId:String
let url:String
let customField1:String
let customField2:String
let customField3:String
let fee:String
let apiCode:String
let statuscode:Int
let statusMessage:String
let errorCode:String
let errorDesc:String
private enum ResponseOuter : String, CodingKey {
case response
case apiCode = "API-Code"
case statuscode = "statuscode"
case respCode
case statusMessage = "statusMessage"
}
enum RespCodeKeys : String, CodingKey {
case errorCode = "ERROR_CODE"
case errorDesc = "ERROR_DESC"
}
private enum Response : String, CodingKey {
case PURCHASE_FREE_SIM_RESPONSE
}
private enum purchaseFreeSimResInfo : String, CodingKey {
case topUp = "TOPUP"
case totalPaymentAmt = "TOTAL_PAYMENT_AMOUNT"
case transId = "TRANSACTION_ID"
case tax = "TAX"
case vat = "VAT"
case shipingAmt = "SHIPPING_AMOUNT"
case itgTransId = "ITG_TRANSACTION_ID"
case chanelTransId = "CHANNEL_TRANSACTION_ID"
case paymentResponse = "PAYMENT_RESPONSE"
case apmResponse = "APM_RESPONSE"
case applicationType = "APPLICATION_TYPE"
case nameorPageId = "NAME_OR_PAGE_ID"
case url = "URL"
case customField1 = "CUSTOM_FIELD_1"
case customField2 = "CUSTOM_FIELD_2"
case customField3 = "CUSTOM_FIELD_3"
case fee = "FEE"
}
init(from decoder :Decoder) throws {
let container = try decoder.container(keyedBy: ResponseOuter.self)
self.apiCode = try container.decodeIfPresent(String.self, forKey: .apiCode) ?? ""
self.statuscode = try container.decodeIfPresent(Int.self, forKey: .statuscode) ?? 600
self.statusMessage = try container.decodeIfPresent(String.self, forKey: .statusMessage) ?? ""
let respCodeCont = try container.nestedContainer(keyedBy: RespCodeKeys.self, forKey: .respCode)
self.errorCode = try respCodeCont.decodeIfPresent(String.self, forKey: .errorCode) ?? ""
self.errorDesc = try respCodeCont.decodeIfPresent(String.self, forKey: .errorDesc) ?? ""
let purcCont = try container.nestedContainer(keyedBy: Response.self, forKey: .response)
let purSimCont = try purcCont.nestedContainer(keyedBy: purchaseFreeSimResInfo.self, forKey: .PURCHASE_FREE_SIM_RESPONSE)
self.topUp = try purSimCont.decodeIfPresent(String.self, forKey: .topUp) ?? ""
self.totalPaymentAmt = try purSimCont.decodeIfPresent(String.self, forKey: .totalPaymentAmt) ?? ""
self.transId = try purSimCont.decodeIfPresent(String.self, forKey: .transId) ?? ""
self.tax = try purSimCont.decodeIfPresent(String.self, forKey: .tax) ?? ""
self.vat = try purSimCont.decodeIfPresent(String.self, forKey: .vat) ?? ""
self.shipingAmt = try purSimCont.decodeIfPresent(String.self, forKey: .shipingAmt) ?? ""
self.itgTransId = try purSimCont.decodeIfPresent(String.self, forKey: .itgTransId) ?? ""
self.chanelTransId = try purSimCont.decodeIfPresent(String.self, forKey: .chanelTransId) ?? ""
self.paymentResponse = try purSimCont.decodeIfPresent(String.self, forKey: .paymentResponse) ?? ""
self.apmResponse = try purSimCont.decodeIfPresent(String.self, forKey: .apmResponse) ?? ""
self.applicationType = try purSimCont.decodeIfPresent(String.self, forKey: .applicationType) ?? ""
self.nameorPageId = try purSimCont.decodeIfPresent(String.self, forKey: .nameorPageId) ?? ""
self.url = try purSimCont.decodeIfPresent(String.self, forKey: .url) ?? ""
self.customField1 = try purSimCont.decodeIfPresent(String.self, forKey: .customField1) ?? ""
self.customField2 = try purSimCont.decodeIfPresent(String.self, forKey: .customField2) ?? ""
self.customField3 = try purSimCont.decodeIfPresent(String.self, forKey: .customField3) ?? ""
self.fee = try purSimCont.decodeIfPresent(String.self, forKey: .fee) ?? ""
}
}
let dataJosn = Data(jsonStr.utf8)
do {
let simDetail = try JSONDecoder().decode(SimPurResponse.self, from: dataJosn)
print(simDetail)
}catch let error {
print(error)
}
我在处理这两种情况时遇到问题。上面完整的代码
只需将您的“尝试”更改为“尝试?”在访问解码器初始化程序块中的nestedContainer时,并在需要的地方添加可选的链接:
init(from decoder :Decoder) throws {
let data = try decoder.container(keyedBy: ResponseOuter.self)
self.apiCode = try data.decodeIfPresent(String.self, forKey: .apiCode) ?? ""
self.statuscode = try data.decodeIfPresent(Int.self, forKey: .statuscode) ?? 600
self.statusMessage = try data.decodeIfPresent(String.self, forKey: .statusMessage) ?? ""
let respCodeCont = try? data.nestedContainer(keyedBy: RespCodeKeys.self, forKey: .respCode)
self.errorCode = try respCodeCont?.decodeIfPresent(String.self, forKey: .errorCode) ?? ""
self.errorDesc = try respCodeCont?.decodeIfPresent(String.self, forKey: .errorDesc) ?? ""
let purcCont = try? data.nestedContainer(keyedBy: Response.self, forKey: .response)
let purSimCont = try purcCont?.nestedContainer(keyedBy: purchaseFreeSimResInfo.self, forKey: .PURCHASE_FREE_SIM_RESPONSE)
self.topUp = try purSimCont?.decodeIfPresent(String.self, forKey: .topUp) ?? ""
self.totalPaymentAmt = try purSimCont?.decodeIfPresent(String.self, forKey: .totalPaymentAmt) ?? ""
self.transId = try purSimCont?.decodeIfPresent(String.self, forKey: .transId) ?? ""
self.tax = try purSimCont?.decodeIfPresent(String.self, forKey: .tax) ?? ""
self.vat = try purSimCont?.decodeIfPresent(String.self, forKey: .vat) ?? ""
self.shipingAmt = try purSimCont?.decodeIfPresent(String.self, forKey: .shipingAmt) ?? ""
self.itgTransId = try purSimCont?.decodeIfPresent(String.self, forKey: .itgTransId) ?? ""
self.chanelTransId = try purSimCont?.decodeIfPresent(String.self, forKey: .chanelTransId) ?? ""
self.paymentResponse = try purSimCont?.decodeIfPresent(String.self, forKey: .paymentResponse) ?? ""
self.apmResponse = try purSimCont?.decodeIfPresent(String.self, forKey: .apmResponse) ?? ""
self.applicationType = try purSimCont?.decodeIfPresent(String.self, forKey: .applicationType) ?? ""
self.nameorPageId = try purSimCont?.decodeIfPresent(String.self, forKey: .nameorPageId) ?? ""
self.url = try purSimCont?.decodeIfPresent(String.self, forKey: .url) ?? ""
self.customField1 = try purSimCont?.decodeIfPresent(String.self, forKey: .customField1) ?? ""
self.customField2 = try purSimCont?.decodeIfPresent(String.self, forKey: .customField2) ?? ""
self.customField3 = try purSimCont?.decodeIfPresent(String.self, forKey: .customField3) ?? ""
self.fee = try purSimCont?.decodeIfPresent(String.self, forKey: .fee) ?? ""
}
希望这会有所帮助。干杯。