7

I am using a free dates API in my project. I am using Decodable to parse the JSON data.

Here I created my struct:-

struct jsonStruct: Decodable {
var message: Bool?
var data: [dateData]
}

struct dateData: Decodable {
var quarter: Int?
var day: String?
var month: String?
}

This is my code to use the decoder:-

let jsonUrlString = "https://api.lrs.org/random-date-generator?lim_quarters=40&source=api-docs"
guard let url = URL(string: jsonUrlString) else { return }
    
URLSession.shared.dataTask(with: url) { (data, reponse, err) in
    guard let data = data  else { return }
    print(data)
        
    do {
        let jsonData = try JSONDecoder().decode([dateData].self, from: data)
        print(jsonData)
    }
    catch let jsonerr {
        print("error serrializing error",jsonerr)
    }
}.resume()

But I am getting an error in my code. It goes in the catch block only and I am getting this error in my console:-

error serrializing error typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))

I don't understand what I am doing wrong in my code.

API Data:-

{
messages: false,
data: {
2018-01-02: {
quarter: 1,
day: "2",
month: "1",
db: "2018-01-02",
long: "Tuesday, January 2nd, 2018",
unix: 1514876400
},
Mithun
  • 2,075
  • 3
  • 19
  • 26
Nilu Sahani
  • 91
  • 1
  • 1
  • 9
  • Possible duplicate of [JSON Decoder Type Mismatch Error](https://stackoverflow.com/questions/50702266/json-decoder-type-mismatch-error) – Nilanshu Jaiswal Dec 01 '18 at 09:06
  • Can you show the raw resonse from the API? It seems that you expected that the JSON payload would contain an array of objects under no key, but the actual payload was different. – Losiowaty Dec 01 '18 at 09:06
  • @Losiowaty... edited my question please check – Nilu Sahani Dec 01 '18 at 09:09
  • Please (learn to) **read** the JSON. It's pretty easy. There are only two collection types, array (`[]`) and dictionary (`{}`). A dictionary becomes a struct/class. As you can see there is no array at all. – vadian Dec 01 '18 at 09:32

2 Answers2

12

You need

struct Root: Codable {
    let messages: Bool
    let data: [String: Datum]
}

struct Datum: Codable {
    let quarter: Int
    let day, month, db, long: String
    let unix: Int
}


let jsonData = try JSONDecoder().decode(Root.self, from: data)
print(jsonData.data.values)

As the root of the json is a dictionary not an array , also data is a dictionary

jsonData.data.forEach {
  if $0 == " 2018-01-02" {
    print($1.month)
  }
}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • But Sir How can I done it by using `Decodable` I want to do with this – Nilu Sahani Dec 01 '18 at 09:21
  • 3
    `Codable` = `Decodable` + `Encodable` it lets you encode and decode , you can make it `Decodable` if you want only it – Shehata Gamal Dec 01 '18 at 09:23
  • It is giving all the values but I want a specific value and I don't know how to do it : ( – Nilu Sahani Dec 01 '18 at 10:06
  • I am getting this in my console `warning: could not execute support code to read Objective-C class data in the process. This may reduce the quality of type information available.` – Nilu Sahani Dec 01 '18 at 10:12
  • check https://stackoverflow.com/questions/50346718/could-not-execute-support-code-to-read-objective-c-class-data-in-the-process-at – Shehata Gamal Dec 01 '18 at 10:16
  • One more question it is giving me all the dictionary value if I only want month value how can I do this? – Nilu Sahani Dec 01 '18 at 10:24
12
struct Job: Decodable {
   var title: String
   var salary: Float

  init(title: String, salary: Float) {
      self.title = title
      self.salary = salary
   }

   enum CodingKeys: String, CodingKey {
     case title, salary
   }
}

struct Person: Decodable {
   var job: Job
   var firstName: String
   var lastName: String
   var age: Int

     init(job: Job, firstName: String, lastName: String, age: Int) {
       self.job = job
       self.firstName = firstName
       self.lastName = lastName
       self.age = age
   }

   enum CodingKeys: String, CodingKey {
       case job = "job_information", firstName = "firstname", lastName = 
       "lastname", age
    }
}

let rawData = """
 {
    "job_information": {
      "title": "iOS Developer",
      "salary": 5000
   },
   "firstname": "John",
   "lastname": "Doe",
    "age": 20
}
 """.data(using: .utf8)!


let person = try JSONDecoder().decode(Person.self, from: rawData)
print(person.firstName) // John
print(person.lastName) // Doe
print(person.job.title) // iOS Developer