问题描述
似乎解码过程停止于在init方法中从容器获取值的时候,甚至没有显示任何错误。我想念什么?
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()
}
我得到的json数据如下:
"jsonData:" Optional({
response = (
{
bdate = "22.9.2000";
"first_name" = Toyota;
id = 616595796;
"last_name" = Camry;
}
);
})
下面是该结构的代码。解码在以“ self.id”开头的行处停止,并且“ getUserInfo”函数的最终结果为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"
}
解决方法
结构中没有什么是可选的,但是JSON缺少两个键。如果您的结构要求所有四个属性都存在,那么除非确实存在所有四个属性,否则您将无法获得该结构的有效实例。
您需要做的是更改您的结构,以使可选属性变为可选属性,并在init方法中使用encodeIfPresent。如果要使用默认值,您甚至可以在此时取消合并。
但是您失败了,因为您的数据与您的结构不匹配。
尝试这样的事情:
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.decodeIfPresent(String.self,forKey: .firstName)
self.lastName = try values.decodeIfPresent(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"
}
}