【问题标题】:Decoding JSON - nil result, no errors解码 JSON - 结果为零,没有错误
【发布时间】:2021-01-16 15:52:39
【问题描述】:

似乎解码过程在 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 消息
  • bdate 不是 Double 它是 String

标签: json swift struct null decoder


【解决方案1】:

您的结构中没有任何内容是可选的,但是您的 JSON 缺少两个键。如果您的结构要求所有四个属性都存在,那么除非确实存在所有四个属性,否则您将无法获得所述结构的有效实例。

你需要做的是改变你的结构,将可选的属性变成可选项,并在你的 init 方法中使用 decodeIfPresent。如果你想要默认值,你甚至可以在那时 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.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"
    }
}

【讨论】:

  • 也按照您的建议进行了尝试,但也没有帮助。然后,我尝试为所有四个键设置 optional ,我得到的结果对所有四个键都是 nil 。像这样: Optional(LoginForm.NetworkService.User(id: nil, firstName: nil, lastName: nil,birthDate: nil))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多