Home > Enterprise >  Decoding fails if keys not present
Decoding fails if keys not present

Time:09-23

Decoding fails if keys not present. How to safely decode if missing keys also.

I have gone through that use Optional or Nil values but still not able to decoding the objects.

Below my Json

{
   "mandatory":true,
   "dynamic_obj":[
      {
         "dt":"2021-09-22 01:29:52",
         "url":"https://res._22_01_29.pdf",
         "desc":"PAN CARD",
         "flag":1,
         "count":"2",
         "field":"pan_card",
         "address":"300-435, Nattu Muthu St, Sheethammal Colony, Venus Colony, Chennai, Tamil Nadu 600018, India",
         "visible":true,
         "latitude":13.0389309,
         "longitude":80.2473746
      },
      {
         "url":"https://res.cloudin/no-image.jpg",
         "desc":"driving License",
         "count":"2",
         "field":"driving_license",
         "visible":true
      }
   ]
}

Model class below

struct Dynamic_obj : Codable {
    var dt : String?
    var url : String?
    let desc : String?
    var flag : Int?
    let count : String?
    let field : String?
    let visible : Bool?
    
    var bankname : String = "NA"
    var pdfPassword : String = "NA"
    var latitude : String = "NA"
    var longitude : String = "NA"
    var address : String = "NA"

    enum CodingKeys: String, CodingKey {

        case dt = "dt"
        case url = "url"
        case desc = "desc"
        case flag = "flag"
        case count = "count"
        case field = "field"
        case visible = "visible"
        
        case bankname = "bankname"
        case pdfPassword = "pdfPassword"
        case latitude = "latitude"
        case longitude = "longitude"
        case address = "address"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        dt = try values.decodeIfPresent(String.self, forKey: .dt)
        url = try values.decodeIfPresent(String.self, forKey: .url)
        desc = try values.decodeIfPresent(String.self, forKey: .desc)
        flag = try values.decodeIfPresent(Int.self, forKey: .flag)
        count = try values.decodeIfPresent(String.self, forKey: .count)
        field = try values.decodeIfPresent(String.self, forKey: .field)
        visible = try values.decodeIfPresent(Bool.self, forKey: .visible)
        
        bankname = try values.decodeIfPresent(String.self, forKey: .bankname) ?? "NA"
        pdfPassword = try values.decodeIfPresent(String.self, forKey: .pdfPassword) ?? "NA"
        latitude = try values.decodeIfPresent(String.self, forKey: .latitude) ?? "NA"
        longitude = try values.decodeIfPresent(String.self, forKey: .longitude) ?? "NA"
        address = try values.decodeIfPresent(String.self, forKey: .address) ?? "NA"
    }

}


                            let decoder = JSONDecoder()
                            do {
                                let responseModel = try decoder.decode(LoanDocxPending.self, from: data)
                                if let mandotory = responseModel.mandatory{
                                    self.visibleDocuments["Identity Proof-~id_proof"] = idProof
                                    self.visibleTitle.append("Identity Proof")
                                }
                            } catch {
                                print("error")
                                
                            }

struct LoanDocxPending :Codable {
    let mandatory : Bool?
    var dynamic_obj : [Dynamic_obj]?

    enum CodingKeys: String, CodingKey {

        case mandatory = "mandatory"
        case dynamic_obj = "dynamic_obj"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        mandatory = try values.decodeIfPresent(Bool.self, forKey: .mandatory)
        dynamic_obj = try values.decodeIfPresent([Dynamic_obj].self, forKey: .dynamic_obj)
    }

}

CodePudding user response:

First of all most of your code is not needed, for example the init methods and almost all CodingKeys.

Second of all as mentioned in the comments rather than printing meaningless literal "error" print the error instance. It will tell you that latitude and longitude are Double, not String.

This model matches the JSON in the question

struct DynamicObj : Codable {
    let dt : String?
    let url, desc : String
    let flag : Int?
    let count, field : String
    let visible : Bool
    
    var bankname, pdfPassword, address : String?
    var latitude, longitude : Double?
}

struct LoanDocxPending :Codable {
    let mandatory : Bool
    var dynamicObj : [DynamicObj]

    enum CodingKeys: String, CodingKey {
        case mandatory,dynamicObj = "dynamic_obj"
    }
}

let decoder = JSONDecoder()
do {
    let responseModel = try decoder.decode(LoanDocxPending.self, from: data)
    print(responseModel.mandatory)
} catch {
    print("error", error)
    
}
  • Related