53

I am developing a project to learn how to parse JSON. I am trying to parse JSON to a struct. I am trying to do it using the code that comes next but I am getting the following error:

Err The data couldn’t be read because it isn’t in the correct format.

What am I doing wrong? Also I tried to use Alamofire but I didn't find way to parse it to struct.

func getData(){ let gitUrl = URL(string: "http://95.46.99.250:9095/api/v1/institution-categories") URLSession.shared.dataTask(with: gitUrl!) { (data, response , error) in let data = data print(data) do { let decoder = JSONDecoder() let gitData = try decoder.decode([Root].self, from: data!) } catch let err { print("\nErr", err.localizedDescription) } }.resume() } 

Struct

struct Root: Codable { let data: [InnerItem] } struct InnerItem:Codable { let id: Int? let image: String? let name: String? private enum CodingKeys : String, CodingKey { case id = "id", image = "image", name = "name" } } 

JSON

{ "data": [ { "id": 1, "name": "Пабы и бары", "image": "http://95.46.99.250:9095/storage/photos/[email protected]" }, { "id": 2, "name": "Кафе", "image": "http://95.46.99.250:9095/storage/photos/[email protected]" }, { "id": 3, "name": "Ночной клуб", "image": "http://95.46.99.250:9095/storage/photos/0201f7523bc2028f174710b51379e432.png" }, { "id": 4, "name": "Ресторан", "image": "http://95.46.99.250:9095/storage/photos/[email protected]" }, { "id": 5, "name": "Караоке-клуб", "image": "http://95.46.99.250:9095/storage/photos/microphone.png" }, { "id": 6, "name": "Суши-бар", "image": "http://95.46.99.250:9095/storage/photos/sushi.png" }, { "id": 7, "name": "Пиццерии", "image": "http://95.46.99.250:9095/storage/photos/pizza.png" }, { "id": 8, "name": "Кальянная", "image": "http://95.46.99.250:9095/storage/photos/c111d1e5ad6b90b61ac36836d220ebba.png" }, { "id": 9, "name": "Общая", "image": "http://95.46.99.250:9095/storage/photos/Group [email protected]" } ] } 
3
  • 8
    [Root].self to Root.self? Your JSON is not an Array at top level. Also, don't use localizedDescription, print the full error, and it should be more explicit then. Commented Jul 17, 2018 at 16:31
  • ... and (although not related to the issue) remove the redundant CodingKeys in InnerItem and all question marks as the JSON dictionaries clearly contain always all keys. image can even be decoded as URL Commented Jul 17, 2018 at 16:35
  • 5
    Don't print the localizedDescription because it has no context. Print the error to see exactly where the serialization failed. Commented Nov 27, 2019 at 10:30

3 Answers 3

128

💡 Troubleshoot coding/decoding errors

When working with codables, instead of printing .localizedDescription, try to print out the error itself! so the compiler describes where the issue exactly is!

do { let decoder = JSONDecoder() let decoded = try decoder.decode([Root].self, from: data!) } catch { // print(error.localizedDescription) // <- ⚠️ Don't use this! print(String(describing: error)) // <- ✅ Use this for debuging! } 

✅ In your case

it will point out that:

  • Decoder tried to decode the root object to an Array but found a Dictionary instead.

So you follow the issue and see that you should replace:

decoder.decode([Root].self, from: data!) 

with:

decoder.decode(Root.self, from: data!) 
Sign up to request clarification or add additional context in comments.

5 Comments

print(String(describing: error)) // <- ✅ Use this for debuging! Thanks man, This line is really helpful .
i am using same but found same issue
Thanks man! This line is great! (I was trying to put a float "disguised" as an int in an int) :/
+1000 for The print statement
+10000 reputations reward from me :)
9

Try this

let gitData = try decoder.decode(Root.self, from: data!) 

Traverse through your data

for singleData in gitData.data where (singleData.name ?? "") == "Cafe" { print(singleData.image) } 

3 Comments

So i get data inside my stuct... Now, how i can get data from InnerItem. For example if InnerItem.name == cafe GET InnerItem.image for this name
This way i will get all images... how i can relate them with name? if InnerItem.name == cafe GET InnerItem.image
If you can traverse, you can add necessary condition as you go. I have added one which will print the URL of the image of which name is "Cafe"
-4

For me, the issue with "The data couldn’t be read because it isn’t in the correct format." was something to do with the specific XLSX file I was trying to use. I created a new XLSX file in Excel, and added it to my project and that worked! Then I just pasted the data I needed from the file that was giving me the error into the newly created XLSX file and it parsed!

 static func load() { guard let filePath = Bundle.main.path(forResource: "test", ofType: "xlsx", inDirectory: nil) else { fatalError("XLSX file not exist") } let file = XLSXFile(filepath: filePath) do { let parseBooks = try? file?.parseWorkbooks() for eachBook in parseBooks! { for (name, path) in try file!.parseWorksheetPathsAndNames(workbook: eachBook) { let worksheet = try file!.parseWorksheet(at: path) let sharedStrings = try file!.parseSharedStrings() print(sharedStrings) } } } catch { print("Error: \(error.localizedDescription)") } } 

1 Comment

Your answer has nothing to do with the question except the same meaningless generic error message. Even in your case replace error.localizedDescription with error to get the underlying real error.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.