UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Day 60 part1 JSONDecoder() issue

Forums > 100 Days of SwiftUI

I was trying to adapt the example from day 49 to work with the data from Day 60. The code below did not work and I am stumped as to why it failed. This is just a quick ContentView to test it. I peaked ahead to the HWS+ solution for this and loadData() works. He defined the Decoder first I think so he could set the Date conversion... but short of that, why does the code below not work? It just displays nothing when I run it:

import SwiftUI

struct Response: Codable {
  var results: [Result]
}

struct Result: Codable {
  let id: UUID
  let isActive: Bool
  let name: String
  let age: Int
  let company: String
  let email: String
  let address: String
  let about: String
  let registered: Date
  let tags: [String]
  let friends: [Friend]

}

struct Friend: Codable, Identifiable {
  var id: UUID
  var name: String
}

struct ContentView: View {
  @State private var results = [Result]()
  var body: some View {
    VStack {
      List(results, id: \.id) { item in
        VStack(alignment: .leading) {
          Text(item.name)
        }
      }
      .task {
        await loadData()
      }
    }
    .padding()
  }

  func loadData() async {
    guard results.isEmpty else { return }

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

    do {

      let (data, _) = try await URLSession.shared.data(from: url)

      if let decodedResponse = try? JSONDecoder().decode(Response.self, from: data) {

        results = decodedResponse.results
      }

    } catch {
      print("Invalid Data")
    }

  }

}

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

3      

Hi! Just modify your loadData() as follows:

    func loadData() async {
        guard results.isEmpty else { return }

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

        // For Date to be decoded use this decoding strategy
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601

        do {

            let (data, _) = try await URLSession.shared.data(from: url)

            // Also you are decoding [Result] NOT Response you can delete it from your code as your are not using it anywhere
            if let decodedResponse = try? decoder.decode([Result].self, from: data) {

                results = decodedResponse
            }

        } catch {
            print("Invalid Data")
        }
    }

3      

So was it failing due to the lack of the date code? I was not even displaying date, so I didnt put it in there. Also, the Day 49 code does not create the decoder first... so I am guessing you have to in order for it to work due to the date?

3      

Yes, you're not displaying the date, however your struct Result contains that property. Once you get the data from the server, decoder still tries to decode but cannot decode that property. As for decoder instantiating before, you need to access .dateDecodingStrategy so that's why you can create it prior, set it up and then use that ready-to-use decoder later in the code.

3      

There are actually two mismatches. Try to use this code to see the error prints.

    func loadData() async {
        guard results.isEmpty else { return }

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

        do {

            let (data, _) = try await URLSession.shared.data(from: url)

            let decodedResponse = try JSONDecoder().decode(Response.self, from: data)

            results = decodedResponse.results

        } catch let error {
            print(error)
        }

    }

You'll see this error printed to console:

// "Expected to decode Dictionary<String, Any> but found an array instead."

Once you change it to:

    func loadData() async {
        guard results.isEmpty else { return }

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

        do {

            let (data, _) = try await URLSession.shared.data(from: url)

            let decodedResponse = try JSONDecoder().decode([Result].self, from: data)

            results = decodedResponse

        } catch let error {
            print(error)
        }

    }

This tells that you cannot decode Date

// "Expected to decode Double but found a string/data instead."

Using try? but not try, insead of throwing an error returns nil. So that is why you don't see any errors printed before

Hope this is more clear now.

3      

ooops I didnt see your comment, I see what is going on... Result vs Response.... one of my bad habits of getting confused on name.

This helped immensely @ygeras. Thank you so much!

3      

This is but one example of why it's best to use more descriptive names than Response and Result.

(Not to mention that Swift has a built-in Result type, which can, in certain circumstances, cause the compiler to get confused. It's almost never a good idea to give one of your own types the same name as a built-in type.)

3      

@roosterboy, I might be wrong, but I think Paul used Result in the one example as that is what the Itunes JSON returned... an array starting with [Result

@ygeras, thank you, I am going to study what you typed above!

Thank you to both of you :D

3      

Granite4Less has been proudly serving Montreal and surrounding areas for years, with over 25 years of combined experience. Granite 4 less is a family company focused on quality and know-how.

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

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.