NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

SOLVED: Decoding JSON data - Error response

Forums > SwiftUI

(i have the below code for decoding JSON data, but i am not getting th response. Instead, I get "Unknown error", which means the URL is correct, but i am not able to define where the problem is.)

import SwiftUI

struct Response: Decodable {
    var users : [User]
}

struct User: Decodable {
    let id: String
    let isActive: Bool
    let name: String
    let age: Int
    let company: String
    let email: String
    let address: String
    let about: String
    let registered: String
    let tags: [String]

    let friends : Friends

    struct Friends: Decodable {
        let id: String
        let name: String
    }
}

struct ContentView: View {
    @State var users = [User]()
    var body: some View {
        List{
            ForEach(users, id: \.id) { item in
                VStack(alignment: .leading){
                    Text(item.name)
                        .font(.headline)
                    Text(item.company)
                }
            }
        }
        .onAppear(perform: loadData)
    }

    func loadData() {
        guard let url = URL(string: "https://www.hackingwithswift.com/samples/friendface.json") else {
            print("Invalid URL")
            return
        }
        let request = URLRequest(url: url)

        URLSession.shared.dataTask(with: request) {data, response, error in
            if let data = data {
                if let decodedResponse = try? JSONDecoder().decode(Response.self, from: data) {
                    DispatchQueue.main.async {
                        self.users = decodedResponse.users
                    }
                    return
                }
            }
            print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")

        }.resume()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

   

hi,

URLSession is not one of my strong suits, but i have two ideas.

(1) the first debugging step is to catch any error thrown in the JSON decoding, perhaps something like this

if let data = data {
  do {
    let decodedResponse = try JSONDecoder().decode(Response.self, from: data)
    DispatchQueue.main.async {
      self.users = decodedResponse.users
     }
  } catch let jsonError as NSError {
    print("JSON decode failed: \(jsonError.localizedDescription)")
  }
  return
}

(2) i see that you have defined let friends: Friends, but Friends is a struct containing a single id and name. did you mean to write let friends: [Friend], where Friend is a struct containing a single id and name?

hope that helps,

DMG

   

As DMG say let friends: Friends should read let friends: [Friends] as you get an array back from the URL json which is causing the error.

   

Hello delawaremathguy & NigelGee ,

your reply is highly appreciated. I revised the code to be let friends: [Friends] instead of let friends: Friends and still the same. However, also applied the below code as per delawaremathguy suggestion, now i get this message: JSON decode failed: The data couldn’t be read because it isn’t in the correct format. So, what does that mean? (keep in mind i am still learning ..)

if let data = data {
  do {
    let decodedResponse = try JSONDecoder().decode(Response.self, from: data)
    DispatchQueue.main.async {
      self.users = decodedResponse.users
     }
  } catch let jsonError as NSError {
    print("JSON decode failed: \(jsonError.localizedDescription)")
  }
  return
}

   

hi,

well, unfortunately, the error "The data couldn’t be read because it isn’t in the correct format" means that the data couldn’t be read because it isn’t in the correct format. (AAARRGGHH!)

(1) it would help to see what the data is that you are reading and whether it matches up against your definition.

(2) you could use a more informative catch handler. replace the generic catch handler

  } catch let jsonError as NSError {
    print("JSON decode failed: \(jsonError.localizedDescription)")
  }

with this extended one that i have used in the past:

} catch DecodingError.keyNotFound(let key, let context) {
    Swift.print("could not find key \(key) in JSON: \(context.debugDescription)")
} catch DecodingError.valueNotFound(let type, let context) {
    Swift.print("could not find type \(type) in JSON: \(context.debugDescription)")
} catch DecodingError.typeMismatch(let type, let context) {
    Swift.print("type mismatch for type \(type) in JSON: \(context.debugDescription)")
} catch DecodingError.dataCorrupted(let context) {
    Swift.print("data found to be corrupted in JSON: \(context.debugDescription)")
} catch let error as NSError {
    NSLog("Error in read(from:ofType:) domain= \(error.domain), description= \(error.localizedDescription)")
}

see if that tells you anything more.

hope that helps,

DMG

1      

Great... sure that told me more, by applying your code, I got this error : type mismatch for type Dictionary<String, Any> in JSON: Expected to decode Dictionary<String, Any> but found an array instead.

then i changed this part of code: let decodedResponse = try JSONDecoder().decode(Response.self, from: data) to: let decodedResponse = try JSONDecoder().decode(Array<User>.self, from: data) and it worked perfectly.

MANY MANY THANKS

   

Tweaks to your original code to make it work. See the comments for explanation of changes.

import SwiftUI

//don't need a Response struct
//struct Response: Decodable {
//    var users : [User]
//}

struct User: Decodable {
    let id: String
    let isActive: Bool
    let name: String
    let age: Int
    let company: String
    let email: String
    let address: String
    let about: String
    let registered: Date  //should be a Date, not a String
    let tags: [String]

    let friends : [Friend]  //array of Friend structs

    struct Friend: Decodable {  // a single Friend, not multiple Friends
        let id: String
        let name: String
    }
}

struct ContentView: View {
    @State var users = [User]()

    var body: some View {
        List{
            ForEach(users, id: \.id) { item in
                VStack(alignment: .leading){
                    Text(item.name)
                        .font(.headline)
                    Text(item.company)
                }
            }
        }
        .onAppear(perform: loadData)
    }

    func loadData() {
        guard let url = URL(string: "https://www.hackingwithswift.com/samples/friendface.json") else {
            print("Invalid URL")
            return
        }
        let request = URLRequest(url: url)

        URLSession.shared.dataTask(with: request) {data, response, error in
            if let data = data {
                //pull out the declaration of the decoder object
                let decoder = JSONDecoder()
                //set how we want to interpret dates in the JSON
                decoder.dateDecodingStrategy = .iso8601
                //decode directly to an array of User structs rather than a Response
                if let decodedResponse = try?
                    decoder.decode([User].self, from: data) {
                    DispatchQueue.main.async {
                        //decodedResponse is now [User] rather than Response.User
                        self.users = decodedResponse
                    }
                    return
                }
            }
            print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")

        }.resume()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

3      

How we can access friend properties?

   

Hacking with Swift is sponsored by Instabug

SPONSORED Catch bugs as soon as they happen and know exactly why a crash occurred. Instabug's SDK grabs all the logs they need to fix bugs, crashes and performance issues in minutes instead of days. Get screenshots, device details, network logs, repro steps, and tons of other critical insights needed to resolve issues and prioritize product backlogs straight from your dashboard. It only takes a minute to integrate!

Get started now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.