在 SwiftUI 中显示 JSON 数据
Displaying JSON Data in SwiftUI
我目前正在开发一个使用 OpenWeatherMap OneCall API 显示天气的应用程序,但我正在努力弄清楚如何显示数据。当我尝试在列表中显示它时,结果只是一个空白列表,没有任何错误消息或任何内容。
这是我的天气结构:
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
}
这是我尝试 API 请求和 JSON 解码:
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()
}
}
这个问题与 SwiftUI 没有特别的关系。
主要问题是,如果添加不得解码的结构成员(id
每小时),则必须指定 CodingKeys。
另一个问题是 rain
在 Daily
和 Hourly
中是可选的,在 Hourly
中是字典。
强烈建议处理任何错误并打印实际的 error
实例。你应该得到
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))
不需要URLRequest
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()
注意:没有理由将所有结构成员都声明为变量。将它们声明为常量 (let
)
我目前正在开发一个使用 OpenWeatherMap OneCall API 显示天气的应用程序,但我正在努力弄清楚如何显示数据。当我尝试在列表中显示它时,结果只是一个空白列表,没有任何错误消息或任何内容。
这是我的天气结构:
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
}
这是我尝试 API 请求和 JSON 解码:
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()
}
}
这个问题与 SwiftUI 没有特别的关系。
主要问题是,如果添加不得解码的结构成员(id
每小时),则必须指定 CodingKeys。
另一个问题是 rain
在 Daily
和 Hourly
中是可选的,在 Hourly
中是字典。
强烈建议处理任何错误并打印实际的 error
实例。你应该得到
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))
不需要URLRequest
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()
注意:没有理由将所有结构成员都声明为变量。将它们声明为常量 (let
)