简体   繁体   中英

Displaying JSON Data in SwiftUI

I'm currently working on an application that displays the weather using the OpenWeatherMap OneCall API but I am struggling to figure out how to display the data. When I try to display it in a list the result is just a blank list with no error messages or anything.

Here are my Weather structs:

import Foundation

struct Weather: Codable {
    var lat: Double
    var lon: Double
    var timezone: String
    var timezone_offset: Int
    var current: Current
    var hourly: [Hourly]
    var daily: [Daily]
}

struct Current: Codable {
    var dt: Int
    var sunrise: Int
    var sunset: Int
    var temp: Double
    var feels_like: Double
    var pressure: Int
    var humidity: Int
    var dew_point: Double
    var uvi: Double
    var clouds: Int
    var visibility: Int
    var wind_speed: Double
    var wind_deg: Int
    var weather: [WeatherData]
    var rain: Double
}

    struct WeatherData: Codable {
        var id: Int
        var main: String
        var description: String
        var icon: String
    }

struct Hourly: Codable, Identifiable {
    var id = UUID()
    var dt: Int
    var temp: Double
    var feels_like: Double
    var pressure: Int
    var humidity: Int
    var dew_point: Double
    var clouds: Int
    var wind_speed: Double
    var wind_deg: Int
    var weather: [WeatherData]
    var rain: Double
}

struct Daily: Codable {
    var dt: Int
    var sunrise: Int
    var sunset: Int
    var temp: TempDetail
    var feels_like: FeelsLikeDetail
    var pressure: Int
    var humidity: Int
    var dew_point: Double
    var wind_speed: Double
    var wind_deg: Double
    var weather: [WeatherData]
    var clouds: Int
    var rain: Double
}

    struct TempDetail: Codable {
        var day: Double
        var min: Double
        var max: Double
        var night: Double
        var eve: Double
        var morn: Double
    }

struct FeelsLikeDetail: Codable {
    var day: Double
    var night: Double
    var eve: Double
    var morn: Double
}

And here is my attempt at an API Request and JSON Decoding:

import SwiftUI

struct ContentView: View {
    @State var hourly = [Hourly]()
    
    func loadData() {
        guard let url = URL(string: "https://api.openweathermap.org/data/2.5/onecall?lat=40.7128&lon=74.0060&units=metric&appid=e69debdf0100132e2076aae6d1c80a2b") 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(Weather.self, from: data) {
                    DispatchQueue.main.async {
                        self.hourly = decodedResponse.hourly
                    }
                    return
                }
            }
            
            print("Fetch Failed: \(error?.localizedDescription ?? "Unknown Error")")
            
        }.resume()
        
    }
    
    var body: some View {
        
        
        List(hourly) { item in
            Text("\(item.temp)")
        }.onAppear(perform: loadData)
        }
    }

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

The question is not particularly related to SwiftUI.

The main issue is that you have to specify CodingKeys if you add a struct member which must not be decoded ( id in Hourly).

Another issue is that rain is optional in Daily and Hourly and is a dictionary in Hourly .

It's highly recommended to handle any error and print the actual error instance. You should get

keyNotFound(CodingKeys(stringValue: "id", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "hourly", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: "id", intValue: nil) ("id").", underlyingError: nil))

And the URLRequest is not needed

 URLSession.shared.dataTask(with: url) { data, response, error in

        if let error = error { print(error); return }
        do {
           let decodedResponse = try JSONDecoder().decode(Weather.self, from: data!)
           DispatchQueue.main.async {
              self.hourly = decodedResponse.hourly
           }
        } catch { print(error) }
        
   }.resume()

Note: There is no reason to declare all struct members as variables. Declare them as constants ( let )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM