4
votes

It works well when "address" array is not empty. But it fails when "address" array is empty. Any help will be highly appreciated. I have struct for Address object. Basically "address" is array of object of type "Address" but when address is empty it fails.

{
    "success": "1",
    "message": "You have succesfully verified your mobile no",
    "details": {
        "customer_id": 825,
        "is_delivery_available": "0",
        "is_registration_complete": "0",
        "is_customer_verified": "0",
        "customer_status": "0",
        "cart_count": "0",
        "name_type": "mr",
        "firstname": "",
        "lastname": "",
        "full_name": "",
        "pincode": "",
        "profile_pic": "",
        "mobile": "8583846677",
        "email": "",
        "address": [

        ],
        "referral_code": ""
    }
}

Above is the JSON I am trying to decode using Codable in Swift4.

import Foundation

struct Signup: Codable {
    var success:String?
    var message:String?
    var details:Details?

    private enum CodingKeys: String, CodingKey { case success, message, details }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        success = try values.decode(String.self, forKey: .success)
        message = try values.decode(String.self, forKey: .message)
        if let _details = try? values.decode(Details.self, forKey: .details) {
            details = _details
        }
    }
}

struct Details: Codable {
    var address:[Address]?
    var cart_count:String?
    var customer_id:String?
    var customer_status:String?
    var email:String?
    var firstname:String?
    var full_name:String?
    var is_customer_verified:String?
    var is_delivery_available:String?
    var is_registration_complete:String?
    var lastname:String?
    var mobile:String?
    var name_type:String?
    var pincode:String?
    var profile_pic:String?
    var referral_code:String?

    private enum CodingKeys: String, CodingKey { case address, cart_count, customer_id, customer_status, email, firstname, full_name, is_customer_verified, is_delivery_available, is_registration_complete, lastname, mobile, name_type, pincode, profile_pic, referral_code }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)

        ****-->>> Issue is in this line. How to handle empty array while decoding. <<<--****
        address = try? values.decode([Address].self, forKey: .address) 

        cart_count = try values.decode(String.self, forKey: .cart_count)
        customer_id = try values.decode(String.self, forKey: .customer_id)
        customer_status = try values.decode(String.self, forKey: .customer_status)
        email = try values.decode(String.self, forKey: .email)
        firstname = try values.decode(String.self, forKey: .firstname)
        full_name = try values.decode(String.self, forKey: .full_name)
        is_customer_verified = try values.decode(String.self, forKey: .is_customer_verified)
        is_delivery_available = try values.decode(String.self, forKey: .is_delivery_available)
        is_registration_complete = try values.decode(String.self, forKey: .is_registration_complete)
        lastname = try values.decode(String.self, forKey: .lastname)
        mobile = try values.decode(String.self, forKey: .mobile)
        name_type = try values.decode(String.self, forKey: .name_type)
        pincode = try values.decode(String.self, forKey: .pincode)
        profile_pic = try values.decode(String.self, forKey: .profile_pic)
        referral_code = try values.decode(String.self, forKey: .referral_code)
    }
}

struct Address: Codable {
    var address_default:String?
    var address_id:String?
    var address_type:String?
    var city:String?
    var customer_id:String?
    var flat_or_house_or_office_no:String?
    var full_address:String?
    var full_name:String?
    var landmark:String?
    var lat:String?
    var lng:String?
    var mobile:String?
    var name_type:String?
    var pincode:String?
    var street_or_society_or_office_name:String?
}

I am stuck into this. How to handle empty array while decoding the json data in Swift4 Codable.

2
decodeIfPresent(_:forKey:) method for decoding - Khushbu
CommonResponse:Signup(success: Optional("1"), message: Optional("You have succesfully verified your mobile no"), details: nil) - not worked. - Alok

2 Answers

5
votes

I came across this problem and I did as below to solve this one.

if let _address = try? values.decode([Address].self, forKey: .address) {
    address = _address
} else {
    address = []
}

You can give it a try.

0
votes

The real issue is that customer_id in Details is Int not String. Decoding an empty array is supposed to work.

Your code is too complicated. Enjoy the magic of Codable and omit all CodingKeys and initializers and declare all struct members as non-optional and as constants

struct Signup: Decodable {
    let success : String
    let message : String
    let details : Details
}

struct Details : Decodable {
    let address : [Address]
    let cart_count : String
    let customer_id : Int
    let customer_status, email, firstname, full_name : String
    let is_customer_verified, is_delivery_available, is_registration_complete : String
    let lastname, mobile, name_type, pincode, profile_pic, referral_code : String
}

struct Address: Decodable {
    let address_default, address_id, address_type, city, customer_id : String
    let flat_or_house_or_office_no, full_address, full_name : String
    let landmark, lat, lng, mobile, name_type, pincode, street_or_society_or_office_name : String
}

You can even name the members camelCased

let cartCount : String
let customerId : Int
...
let isRegistrationComplete : String

and pass the convertFromSnakeCase key decoding strategy

decoder.keyDecodingStrategy = .convertFromSnakeCase

Still no extra code!