Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I am trying to parse a response using the JSONDecoder . If there is value for the corresponding key then it goes well, but if there is null value for a key then it fails to compile with the following error.

valueNotFound(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "Results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "VehicleName", intValue: nil)], debugDescription: "Expected String value but found null instead.", underlyingError: nil))

guard let obj = try? JSONDecoder().decode(ShipmentsResponse.self, from: json) else {return}

here is the Shipment class that i defied

class ShipmentResponse : Codable {
    var ItemId: String = ""
    var VehicleName: String  = ""
    var VehicleNumber: String  = ""
    convenience required init(from decoder: Decoder) throws
        self.init()
        let values = try decoder.container(keyedBy: CodingKeys.self)
        ItemId = try values.decode(String.self, forKey: .ItemId)
            _ = try values.decode(String.self, forKey: .VehicleName)
        } catch {
            print(error)
        VehicleName = try values.decode(String.self, forKey: .VehicleName)
        VehicleNumber = try values.decode(String.self, forKey: .VehicleNumber)

Here is the json

"ItemId": "8af66c87-9099-42a7-8a34-39def02160ac", "VehicleName": null, "VehicleNumber": null

Expected value is string but we are getting null in the response. So the decoder throws an error if it's going to decode a null value to a non-optional type. So, handle it by making the empty string in the parameters.

Model code:

class ShipmentResponse : Codable {
    var itemId: String
    var vehicleName: String
    var vehicleNumber: String
    enum CodingKeys: String, CodingKey {
        case itemId = "ItemId"
        case vehicleName = "VehicleName"
        case vehicleNumber = "VehicleNumber"
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.itemId = try container.decodeIfPresent(String.self, forKey: .itemId) ?? ""
        self.vehicleName = try container.decodeIfPresent(String.self, forKey: .vehicleName) ?? ""
        self.vehicleNumber = try container.decodeIfPresent(String.self, forKey: .vehicleNumber) ?? ""
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(itemId, forKey: .itemId)
        try container.encode(vehicleName, forKey: .vehicleName)
        try container.encode(vehicleNumber, forKey: .vehicleNumber)

JSON parsing:

let data = """
    "ItemId": "8af66c87-9099-42a7-8a34-39def02160ac",
    "VehicleName": null,
    "VehicleNumber": null
""".data(using: String.Encoding.utf8)!
    let jsonData = try JSONDecoder().decode(ShipmentResponse.self, from: data)
    print("\(jsonData.itemId) \(jsonData.vehicleNumber)")
} catch let error {
    print(error)
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.