Backend returns custom JSON value for location. As shown in example:
{
"location": (54.000000, 21.000000)
}
For parsing JSON I am using this code:
let json = """
{
"location": (54.000000, 21.000000)
}
"""
struct Location: Codable {
var latitude: Double
var longitude: Double
}
let dataJson = json.data(using: .utf8)!
let location = try? JSONDecoder().decode(Location.self, from: dataJson)
When I am trying to create Location object using JSONDecoder it gives me an error: The given data was not valid JSON.
dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 18." UserInfo={NSDebugDescription=Invalid value around character 18.})))
I know that it is not valid JSON. Which methods to override that I could parse invalid JSON values?
If the third party generates the invalid JSON in a consistent manner, you can use regex to to make fix it back to valid JSON. This is not fool-proof. It can fail if the JSON is simply formatted differently. The best course of action is to ask the third party to correct their back-end.
You can use regex to replace the round brackets with square brackets:
var json = """
{
"location": (54.000000, 21.000000)
}
"""
let regex = try! NSRegularExpression(pattern: "\\\"location\\\":\\s*\\((.+?)\\)", options: [])
let fullRange = NSRange(..<json.endIndex, in: json)
json = regex.stringByReplacingMatches(in: json, options: [], range: fullRange, withTemplate: "\"location\": [$1]")
You also need to add a custom decoder to your Location
struct since it is encoded as an array now:
struct Location: Decodable {
var latitude: Double
var longitude: Double
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
latitude = try container.decode(Double.self)
longitude = try container.decode(Double.self)
}
}
Example of decoding:
struct Response: Decodable {
var location: Location
}
let dataJson = json.data(using: .utf8)!
let location = try JSONDecoder().decode(Response.self, from: dataJson)