OpenWeather One Call API 坐标未加载
OpenWeather One Call API coord not loading
在我的天气应用程序中,我调用了 OpenWeather One Call API。
在我的 Xcode 调试控制台中,我得到:
Error getting weather: keyNotFound(CodingKeys(stringValue: "coord", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"coord\", intValue: nil) (\"coord\").", underlyingError: nil))
我在模拟器和物理设备上测试了这个应用程序。没用。
请提供有关如何解决此问题的信息。非常感谢。
这是我的代码中解析 JSON:
的部分
class WeatherManager {
// HTTP request to get the current weather depending on the coordinates we got from LocationManager
func getCurrentWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees) async throws -> ResponseBody {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/onecall?lat=\(latitude)&lon=\(longitude)&units=metric&appid=") else { fatalError("Missing URL") }
let urlRequest = URLRequest(url: url)
let (data, response) = try await URLSession.shared.data(for: urlRequest)
guard (response as? HTTPURLResponse)?.statusCode == 200 else { fatalError("Error while fetching data") }
let decodedData = try JSONDecoder().decode(ResponseBody.self, from: data)
return decodedData
}
}
这是 ResponseBody 的前几部分:
struct ResponseBody: Decodable {
public let lat, lon: Double
var weather: [WeatherResponse]
var current: CurrentResponse
var name: String
var wind: WindResponse
var sun: SunResponse
struct WeatherResponse: Decodable {
var id: Double
var main: String
var description: String
var icon: String
}
不胜感激。
OpenWeatherMap 是 well documented,请阅读文档。
有多个不同的 API,我猜你的结构代表另一个 API 数据。
基本的 OneCall 根对象(省略 minutely
、daily
、hourly
和 alerts
)是
struct OneCall: Decodable {
let lat, lon: Double
let timezone : String
let timezoneOffset : Int
let current: Current
}
而后代Current
和Weather
是
struct Current: Decodable {
let dt, sunrise, sunset : Date
let temp, feelsLike, dewPoint, uvi, windSpeed : Double
let pressure, humidity, clouds, visibility, windDeg : Int
let windGust : Double?
let weather : [Weather]
}
struct Weather: Decodable, Identifiable, CustomStringConvertible {
let id : Int
let main, description, icon : String
}
dt
、sunrise
和 sunset
被解码为 Date
,并且 snake_case 键通过应用适当的解码策略被转换为驼峰命名法。
我强烈建议使用 URLComponents
和 URLQueryItems
构建 URL,apiKey
是 API 关键常量。
let apiKey = "•••••••••"
enum WeatherManagerError : Error { case missingURL, badResponse }
class WeatherManager {
// HTTP request to get the current weather depending on the coordinates we got from LocationManager
func getCurrentWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees) async throws -> OneCall {
var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/onecall")!
let queryItems = [URLQueryItem(name: "appid", value: apiKey),
URLQueryItem(name: "lat", value: "\(latitude)"),
URLQueryItem(name: "lon", value: "\(longitude)"),
URLQueryItem(name: "units", value: "metric")]
urlComponents.queryItems = queryItems
guard let url = urlComponents.url else { throw WeatherManagerError.missingURL }
let (data, response) = try await URLSession.shared.data(from: url)
guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw WeatherManagerError.badResponse }
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .secondsSince1970
return try decoder.decode(OneCall.self, from: data)
}
}
在我的天气应用程序中,我调用了 OpenWeather One Call API。 在我的 Xcode 调试控制台中,我得到:
Error getting weather: keyNotFound(CodingKeys(stringValue: "coord", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"coord\", intValue: nil) (\"coord\").", underlyingError: nil))
我在模拟器和物理设备上测试了这个应用程序。没用。
请提供有关如何解决此问题的信息。非常感谢。
这是我的代码中解析 JSON:
的部分class WeatherManager {
// HTTP request to get the current weather depending on the coordinates we got from LocationManager
func getCurrentWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees) async throws -> ResponseBody {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/onecall?lat=\(latitude)&lon=\(longitude)&units=metric&appid=") else { fatalError("Missing URL") }
let urlRequest = URLRequest(url: url)
let (data, response) = try await URLSession.shared.data(for: urlRequest)
guard (response as? HTTPURLResponse)?.statusCode == 200 else { fatalError("Error while fetching data") }
let decodedData = try JSONDecoder().decode(ResponseBody.self, from: data)
return decodedData
}
}
这是 ResponseBody 的前几部分:
struct ResponseBody: Decodable {
public let lat, lon: Double
var weather: [WeatherResponse]
var current: CurrentResponse
var name: String
var wind: WindResponse
var sun: SunResponse
struct WeatherResponse: Decodable {
var id: Double
var main: String
var description: String
var icon: String
}
不胜感激。
OpenWeatherMap 是 well documented,请阅读文档。
有多个不同的 API,我猜你的结构代表另一个 API 数据。
基本的 OneCall 根对象(省略 minutely
、daily
、hourly
和 alerts
)是
struct OneCall: Decodable {
let lat, lon: Double
let timezone : String
let timezoneOffset : Int
let current: Current
}
而后代Current
和Weather
是
struct Current: Decodable {
let dt, sunrise, sunset : Date
let temp, feelsLike, dewPoint, uvi, windSpeed : Double
let pressure, humidity, clouds, visibility, windDeg : Int
let windGust : Double?
let weather : [Weather]
}
struct Weather: Decodable, Identifiable, CustomStringConvertible {
let id : Int
let main, description, icon : String
}
dt
、sunrise
和 sunset
被解码为 Date
,并且 snake_case 键通过应用适当的解码策略被转换为驼峰命名法。
我强烈建议使用 URLComponents
和 URLQueryItems
构建 URL,apiKey
是 API 关键常量。
let apiKey = "•••••••••"
enum WeatherManagerError : Error { case missingURL, badResponse }
class WeatherManager {
// HTTP request to get the current weather depending on the coordinates we got from LocationManager
func getCurrentWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees) async throws -> OneCall {
var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/onecall")!
let queryItems = [URLQueryItem(name: "appid", value: apiKey),
URLQueryItem(name: "lat", value: "\(latitude)"),
URLQueryItem(name: "lon", value: "\(longitude)"),
URLQueryItem(name: "units", value: "metric")]
urlComponents.queryItems = queryItems
guard let url = urlComponents.url else { throw WeatherManagerError.missingURL }
let (data, response) = try await URLSession.shared.data(from: url)
guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw WeatherManagerError.badResponse }
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .secondsSince1970
return try decoder.decode(OneCall.self, from: data)
}
}