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

SOLVED: My data does not show

Forums > SwiftUI

Hello, I wanted a little bit of rest rom the 100 days and I wanted to practice writing my own, AppStore-shippable app. However it seems I am not ready yet lol. Here is my API class:

//
//  TyfloAPI.swift
//  Tyflocentrum
//
//  Created by Arkadiusz Świętnicki on 19/10/2022.
//

import Foundation

final class TyfloAPI: ObservableObject {
    private let session: URLSession
    private let tyfloPodcastURL = "https://tyflopodcast.net/wp-json/"
    private let tyfloWorldURL = "https://tyfloswiat.pl/wp-json/"
    static let shared = TyfloAPI()
    private init() {
        session = URLSession.shared
    }
    func getLatestPodcasts() async -> [Podcast] {
        guard let url = URL(string: tyfloPodcastURL+"wp/v2/posts/?per_page=100") else {
            print("Failed to create URL")
            return [Podcast]()
        }
        do {
            let (data, _) = try await session.data(from: url)
            if let decodedResponse = try? JSONDecoder().decode(Podcast.self, from: data) {
                return [decodedResponse]
            }
            return [Podcast]()
        }
        catch {
            print("An error has occurred.")
            return [Podcast]()
        }

    }
}
  1. I know I should use optionals for return type and not just return an empty array (I will fix that before shipping).
  2. The clas is Observable because since its a singleton I want to include him in the environment later. No matter though, here;s my view
    
    //
    //  NewsView.swift
    //  Tyflocentrum
    //
    //  Created by Arkadiusz Świętnicki on 17/10/2022.
    //

import Foundation import SwiftUI struct NewsView: View { private let api = TyfloAPI.shared @State private var podcasts = [Podcast]() var body: some View {

    NavigationView {
        VStack {
            List {
                ForEach(podcasts) {item in
                    Text(item.title.rendered)
                }.task {
                    await podcasts = api.getLatestPodcasts()
                }
            }
        }.navigationTitle("nowości")
    }
}

}


Of course, this is a test of the view, and the look will be improved, however as for now, no data is loaded.
What did I do wrong?

2      

In getLatestPodcasts, try putting some print statements to try to debug where things are going wrong...

2      

Replace this code:

do {
    let (data, _) = try await session.data(from: url)
    if let decodedResponse = try? JSONDecoder().decode(Podcast.self, from: data) {
        return [decodedResponse]
    }
    return [Podcast]()
}
catch {
    print("An error has occurred.")
    return [Podcast]()
}

with this:

do {
    let (data, _) = try await session.data(from: url)
    let decodedResponse = try JSONDecoder().decode(Podcast.self, from: data)
    return [decodedResponse]
}
catch {
    print(error)
    return [Podcast]()
}

In the first snippet, the use of try? swallows any error by turning it into nil and you lose useful information about what went wrong. You might get to the catch clause if the session.data(from:) call fails, but a failure at your decode(_:from:) call will never hit the catch. There is no need to use do {} catch {} if you are also going to use try?.

I would recommend never using try? when decoding JSON that is not 100% under your control. Instead, set up proper error handling so you can see what went wrong in the event of an error.

(At first glance, I'm betting the problem is that the JSON is returning an array of Podcasts but you are telling the decoder that you want a single Podcast by using Podcast.self.)

Also, this:

I know I should use optionals for return type and not just return an empty array (I will fix that before shipping).

I would suggest keeping the return value as an empty array. An Optional isn't really necessary here, as an empty array gets the semantic idea across perfectly fine and it works with SwiftUI's ForEach or List much better than an Optional does. If you give an empty array to a ForEach or a List, they simply won't display anything.

2      

I have got an error that the data is in an incorrect format. So I have decide to rewrite my model like so // // Podcast.swift // Tyflocentrum // // Created by Arkadiusz Świętnicki on 24/10/2022. //

import Foundation

struct PodcastResponse: Codable { var podcasts: [Podcast] } struct Podcast: Codable, Identifiable { struct PodcastTitle: Codable { var rendered: String } var id: Int var date: Date var title: PodcastTitle var excerpt: PodcastTitle

}

However I still get the same error. You can see my JSON when you go to tyflopodcast.net/wp-json/wp/v2/posts?per_page=100

2      

When posting code to these forums, place three backticks ``` on the line before your code and three backticks ``` on the line after your code so that it will be formatted properly. You can also highlight an entire code block and click the </> button on the toolbar to wrap the block for you.

This makes it far easier to read and also makes it easier for other posters to copy/paste the code in order to test solutions and such.

Doing this will ensure that you end up with something like this:

//
// Podcast.swift
// Tyflocentrum
//
// Created by Arkadiusz Świętnicki on 24/10/2022.
//

import Foundation

struct PodcastResponse: Codable {
    var podcasts: [Podcast]
}

struct Podcast: Codable, Identifiable {
    struct PodcastTitle: Codable {
        var rendered: String
    }

    var id: Int
    var date: Date
    var title: PodcastTitle
    var excerpt: PodcastTitle
}

instead of this:

// // Podcast.swift // Tyflocentrum // // Created by Arkadiusz Świętnicki on 24/10/2022. //

import Foundation

struct PodcastResponse: Codable { var podcasts: [Podcast] } struct Podcast: Codable, Identifiable { struct PodcastTitle: Codable { var rendered: String } var id: Int var date: Date var title: PodcastTitle var excerpt: PodcastTitle

}

However I still get the same error. You can see my JSON when you go to tyflopodcast.net/wp-json/wp/v2/posts?per_page=100

2      

I am sorry for the inconvenience. I am blind and the forum editor is not very well accessible with the MacOS VoiceOver.

2      

Try something like this:

import SwiftUI

final class TyfloAPI: ObservableObject {
    private let session: URLSession
    private let tyfloPodcastURL = "https://tyflopodcast.net/wp-json/"
    private let tyfloWorldURL = "https://tyfloswiat.pl/wp-json/"
    static let shared = TyfloAPI()
    private init() {
        session = URLSession.shared
    }
    func getLatestPodcasts() async -> [Podcast] {
        guard let url = URL(string: tyfloPodcastURL+"wp/v2/posts/?per_page=100") else {
            print("Failed to create URL")
            return [Podcast]()
        }
        do {
            let (data, _) = try await session.data(from: url)
            //we arwe looking for an array of Podcasts
            let decodedResponse = try JSONDecoder().decode([Podcast].self, from: data)
            return decodedResponse
        }
        catch {
            print(error)
            return [Podcast]()
        }

    }
}

struct Podcast: Codable, Identifiable {
    struct PodcastTitle: Codable {
        var rendered: String
    }

    var id: Int
    var date: String //the date in the JSON is not formatted as a Date so let's just fall back to String
    var title: PodcastTitle
    var excerpt: PodcastTitle
}

struct TyfloPodcastView: View {
    private let api = TyfloAPI.shared
    @State private var podcasts = [Podcast]()

    var body: some View {
        NavigationView {
            VStack {
                List {
                    ForEach(podcasts) {item in
                        Text(item.title.rendered)
                    }
                }
                //put the task modifier on the list
                .task {
                    await podcasts = api.getLatestPodcasts()
                }
            }
            .navigationTitle("nowości")
        }
    }
}

struct TyfloPodcastView_Previews: PreviewProvider {
    static var previews: some View {
        TyfloPodcastView()
    }
}

2      

Oh, so the date was the problem, as I tried your approach. I would have never guessed. Thank you so much!

3      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.