Decoding dynamic JSON structure in swift 4

后端 未结 4 1620
情深已故
情深已故 2021-01-28 16:43

I have the following issue that I\'m not sure how to handle.

My JSON response can look like this:

{ 
  \"data\": {
      \"id\": 7,
      \"         


        
4条回答
  •  感动是毒
    2021-01-28 17:08

    If data can be a single object or an array write a custom initializer which decodes first an array, if a type mismatch error occurs decode a single object. data is declared as an array anyway.

    As token appears only in a single object the property is declared as optional.

    struct ApiData: Decodable {
        let data : [DataObject]
        let error : String?
    
        private enum CodingKeys : String, CodingKey { case data, error }
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            do {
                data = try container.decode([DataObject].self, forKey: .data)
            } catch DecodingError.typeMismatch {
                data = [try container.decode(DataObject.self, forKey: .data)]
            }
            error = try container.decodeIfPresent(String.self, forKey: .error)
        }
    }
    
    
    struct DataObject: Decodable {
        let userId : Int
        let token : String?
    
        private enum CodingKeys: String, CodingKey { case userId = "id", token }
    }
    

    Edit: Your code to receive the data can be improved. You should add a better error handling to return also all possible errors:

    func makeDataTaskWith(with urlRequest: URLRequest, completion: @escaping(ApiData?, Error?) -> Void) {
        let config = URLSessionConfiguration.default
        let session = URLSession(configuration: config)
    
        session.dataTask(with: urlRequest) {
            (data, response, error) in
            if let error = error { completion(nil, error); return }
    
            if let responseCode = response as? HTTPURLResponse {
                print("Response has status code: \(responseCode.statusCode)")
            }
    
            do {
                let retreived = try NetworkManager.shared.decoder.decode(ApiData.self, from: data!)
                completion(retreived, nil)
            } catch {
                print("Decoder error: ", error)
                completion(nil, error)
            }
            }.resume()
    }
    

提交回复
热议问题