Reputation: 291
I am new to swift programming..was able to obtain a successful response from URLSession but I am unable to parse (decode) the data object to my desired APIResponse Structure
this is my url request code:
func load(urlRequest: URLRequest, withCompletion completion: @escaping (_ response: APIResponse) -> Void) {
let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
guard error == nil else {
print("Error fetching data from server\nERROR: \(String(describing: error))")
return
}
guard let jsonData = data else {
print("Response Data is empty")
return
}
printResponseBody(response: data)
let decoder = JSONDecoder()
let response = try? decoder.decode(APIResponse.self, from: jsonData)
guard let decodedResponse = response else {
print("Unable to parse data from response")
return
}
print("Decoded Response: ", decodedResponse)
DispatchQueue.main.async { completion(decodedResponse) }
}
task.resume()
}
and here is my response structure which i need the response data to map to to use in my code:
struct APIResponse: Codable {
let responseCode: Int
let data: ResultSet
let meta: Meta
enum CodingKeys: String, CodingKey {
case responseCode = "response_code"
case data, meta
}
}
// MARK: - DataClass
struct ResultSet: Codable {
let appVersionUpdate: String
let offers: [Offer]
let rate: Int
enum CodingKeys: String, CodingKey {
case appVersionUpdate = "app_version_update"
case offers, rate
}
}
// MARK: - Offer
struct Offer: Codable, Identifiable {
let id: Int
let title: String
let image: String?
let r, resultCount: Double
enum CodingKeys: String, CodingKey {
case id, r = "r"
case title, image
case resultCount = "result_count"
}
}
// MARK: - Meta
struct Meta: Codable {
let apiVersion: Int
enum CodingKeys: String, CodingKey {
case apiVersion = "api_version"
}
this is the json from server which I am trying to decode
{
"response_code": 0,
"data": {
"app_version_update": "",
"offers": [
{
"title": "Special Scheme1",
"image": "http://59.145.109.138:11101/Offers/BGL_banner_1080_x_540_1.jpg",
"r": 1.0,
"result_count": 5.0
},
{
"title": "test 1",
"image": "http://59.145.109.138:11101/Offers/Yoho-National-Park2018-10-27_10-10-52-11.jpg",
"r": 2.0,
"result_count": 5.0
},
{
"title": "Offer Test 1234444",
"image": "http://59.145.109.138:11101/Offers/Stanley-Park2018-10-27_10-11-27-44.jpg",
"r": 3.0,
"result_count": 5.0
}
],
"rate": 2000
},
"meta": {
"api_version": 2.0
}
}
whenever i run this code i am getting the "unable to parse data from response" error. Would really appreciate if someone tells me what I am doing wrong here
Upvotes: 2
Views: 2566
Reputation: 2104
The problem is with decoding the id
in Offer
. Replace your Offer
with this:
struct Offer: Codable, Identifiable {
let id: Int
let title: String
let image: String?
let r, resultCount: Int
enum CodingKeys: CodingKey {
case id, r, title, image, resultCount
var stringValue: String {
switch self {
case .id, .r: return "r"
case .title: return "title"
case .image: return "image"
case .resultCount: return "result_count"
}
}
}
}
enum CodingKeys: String, CodingKey
, the raw value for each case Must be different from the other or the Xcode will complain. In your case it didn't complain because id
is the requirement of the Identifiable
protocol, but it also didn't even use the raw value that you set for id
. If you want to use the same key for 2 different variables, you should do the same thing i did above.This will work the same as the your code, but is quite cleaner:
struct Offer: Codable, Identifiable {
var id: Int { r }
let title: String
let image: String?
let r, resultCount: Int
enum CodingKeys: String, CodingKey {
case r, title, image, resultCount
}
}
It basically says everytime you need id
, get it from r
. You can also remove the stringValue
in CodingKeys
as i did, and use the CodingKeys: String
conformation.
Upvotes: 1