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)
do {
_ = 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
}
The error is very clear that.
Expected String value but found null instead
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)!
do {
let jsonData = try JSONDecoder().decode(ShipmentResponse.self, from: data)
print("\(jsonData.itemId) \(jsonData.vehicleNumber)")
} catch let error {
print(error)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With