It seems like the decoding process stops at the point of getting the values from the container in the init method and not even showing any errors. What am I missing?
func getUserInfo(userId: Int, completion: @escaping (User?, Error?) -> Void) {
guard let token = Session.shared.token else { return }
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration)
var urlConstructor = URLComponents()
urlConstructor.scheme = "https"
urlConstructor.host = "api.vk.com"
urlConstructor.path = "/method/users.get"
urlConstructor.queryItems = [
URLQueryItem(name: "user_ids", value: "\(userId)"),
URLQueryItem(name: "fields", value: "bdate"),
URLQueryItem(name: "access_token", value: "\(token)"),
URLQueryItem(name: "v", value: "5.68")
]
let decoder = JSONDecoder()
let task = session.dataTask(with: urlConstructor.url!) { (data, response, error) in
let jsonData = try? JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments)
debugPrint("jsonData:", jsonData)
guard let dataResponse = data, error == nil else {
debugPrint(error?.localizedDescription ?? "Response Error")
return }
do {
let result = try decoder.decode(User.self, from: dataResponse)
debugPrint("result:", result)
completion(result, nil)
} catch (let error) {
completion(nil, error)
}
}
task.resume()
}
The json data I get looks like this:
"jsonData:" Optional({
response = (
{
bdate = "22.9.2000";
"first_name" = Toyota;
id = 616595796;
"last_name" = Camry;
}
);
})
Below is the code for the struct. Decoding stops at the line starting with "self.id" and the end result of the "getUserInfo" func is nil.
struct User: Decodable {
let id: Int
let firstName: String
let lastName: String
let birthDate: Double
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.id = try values.decode(Int.self, forKey: .id)
self.firstName = try values.decode(String.self, forKey: .firstName)
self.lastName = try values.decode(String.self, forKey: .lastName)
self.birthDate = try values.decode(Double.self, forKey: .birthDate)
}
}
enum CodingKeys: String, CodingKey {
case id
case firstName = "first_name"
case lastName = "last_name"
case birthDate = "bdate"
}
Nothing you have in your struct is optional, but your JSON is missing two keys. If your struct requires all four properties to be present, you won't get a valid instance of said struct unless all four properties are indeed present.
What you need to do is change your struct to make the properties that are optional into optionals and use decodeIfPresent in your init method. You can even nil coalesce at that point too if you want default values.
But you're failing because your data doesn't match your struct.
Try something like this: