Null values decoding works well with Codable protocol, but when I have JSON that has NaN, everything crashes, how do I solve this?
I have spent last couple days, but did not find a solution.
Say, we have following code:
[
{
"id": 1
"apples": 193,
"oranges": NaN,
"bananas": null,
"pineapples": 405,
"watermelons": 13
"comment": "oranges and bananas have invalid values"
}
]
And this struct:
struct Fruits: Codable, Identifiable {
var id: Int
var apples: Int?
var oranges: Int?
var bananas: Int?
var pineapples: Int?
var watermelons: Int?
var comment: String?
}
How to decode this with no crashes?
CodePudding user response:
Use decode if present As we know oranges is integer type
import Foundation
struct Fruits : Codable, Identifiable {
let id : Int?
let apples : Int?
let oranges : Int?
let bananas : Int?
let pineapples : Int?
let watermelons : Int?
let comment : String?
enum CodingKeys: String, CodingKey {
case id = "id"
case apples = "apples"
case oranges = "oranges"
case bananas = "bananas"
case pineapples = "pineapples"
case watermelons = "watermelons"
case comment = "comment"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decodeIfPresent(Int.self, forKey: .id)
apples = try values.decodeIfPresent(Int.self, forKey: .apples)
oranges = try values.decodeIfPresent(Int.self, forKey: .oranges)
bananas = try values.decodeIfPresent(Int.self, forKey: .bananas)
pineapples = try values.decodeIfPresent(Int.self, forKey: .pineapples)
watermelons = try values.decodeIfPresent(Int.self, forKey: .watermelons)
comment = try values.decodeIfPresent(String.self, forKey: .comment)
}
}
if there is some value against fruits between 0 to n then it will show the value otherwise it will return nil so you can easily achieve
CodePudding user response:
since your data is not valid json, you could try this approach where the original data is made into valid json, works very well for me.
Note: you are also missing a comma after id
and watermelons
struct ContentView: View {
var body: some View {
Text("testing")
.onAppear{
let json = """
[
{
"id": 1,
"apples": 193,
"oranges": NaN,
"bananas": null,
"pineapples": 405,
"watermelons": 13,
"comment": "oranges and bananas have invalid values"
}
]
"""
// simulated api data
let data = json.data(using: .utf8)!
// convert to string
let jsString = String(data: data, encoding: .utf8)!
// convert back to data after replacements
let newData = jsString.replacingOccurrences(of: "NaN", with: "null").data(using: .utf8)!
do {
let fruits = try JSONDecoder().decode([Fruits].self, from: newData)
print("\n---> fruits: \(fruits)")
} catch (let error) {
print("\n---> error: \(error)")
}
}
}
}