Search code examples
iosswiftuixcode11swift5swiftui-list

Getting JSON from a public API to render in a list view in SwiftUI


I'm trying to get the data from a Rest Api to download and render in a list view in SwiftUI. I think I manage to get the JSON to download and assign to all the relevant Structs correctly but nothing displays in the list view on the simulator when I go to build it.

I'm not even sure I need to have the 'Enum CodingKeys in there.

Can anyone point out where I may be going wrong?

import Foundation
import SwiftUI
import Combine


struct ContentView: View {
    @ObservedObject var fetcher = LaunchDataFetcher()

    var body: some View {
        VStack {
            List(fetcher.launches) { launch in
                VStack (alignment: .leading) {
                    Text(launch.mission_name)
                    Text(launch.details)
                        .font(.system(size: 11))
                        .foregroundColor(Color.gray)
                }
            }
        }
    }
}

public class LaunchDataFetcher: ObservableObject {

    @Published var launches = [launch]()
    init(){
        load()
    }

    func load() {
        let url = URL(string: "https://api.spacexdata.com/v3/launches")!
        URLSession.shared.dataTask(with: url) {(data,response,error) in
            do {
                if let d = data {
                    let decodedLists = try JSONDecoder().decode([launch].self, from: d)
                    DispatchQueue.main.async {
                        self.launches = decodedLists
                    }
                }else {
                    print("No Data")
                }
            } catch {
                print ("Error")
            }

        }.resume()

    }
}

struct launch: Codable {
    public var flight_number: Int
    public var mission_name: String
    public var details: String

    enum CodingKeys: String, CodingKey {
           case flight_number = "flight_number"
           case mission_name = "mission_name"
           case details = "details"
        }
}

// Now conform to Identifiable
extension launch: Identifiable {
    var id: Int { return flight_number }
}


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

Solution

  • First of all, I try to find which error of your code and recognize the launch.details of response data somewhere have null. So that I just mark this property Optional and it work.

    For more details, you can refer below code :

    struct launch: Codable {
        public var flight_number: Int
        public var mission_name: String
        public var details: String?
    
        enum CodingKeys: String, CodingKey {
               case flight_number = "flight_number"
               case mission_name = "mission_name"
               case details = "details"
            }
    }
    

    At catch line, get the error message to know exactly what's happen

    func load() {
            let url = URL(string: "https://api.spacexdata.com/v3/launches")!
            URLSession.shared.dataTask(with: url) {(data,response,error) in
                do {
                    if let d = data {
                        let decodedLists = try JSONDecoder().decode([launch].self, from: d)
                        DispatchQueue.main.async {
                            print(decodedLists)
                            self.launches = decodedLists
                        }
                    }else {
                        print("No Data")
                    }
                } catch let parsingError {
                    print ("Error", parsingError)
                }
    
            }.resume()
        }
    

    Hope this help!