问题
I am building a small swift weather app using the openweatherAPI and I am running into some issues trying to parse the JSON. I have used the following function to parse the get and parse the json.
Below is my weather data struct:
struct WeatherData: Codable {
let coord: Coord
let weather: [Weather]
let base: String
let main: Main
let visibility: Int
let wind: Wind
let clouds: Clouds
let dt: Int
let sys: Sys
let id: Int
let name: String
let cod: Int
}
struct Clouds: Codable {
let all: Int
}
struct Coord: Codable {
let lon, lat: Double
}
struct Main: Codable {
let temp: Double
let pressure, humidity: Int
let tempMin, tempMax: Double
enum CodingKeys: String, CodingKey {
case temp, pressure, humidity
case tempMin = "temp_min"
case tempMax = "temp_max"
}
}
struct Sys: Codable {
let type, id: Int
let message: Double
let country: String
let sunrise, sunset: Int
}
struct Weather: Codable {
let id: Int
let main, description, icon: String
}
struct Wind: Codable {
let speed: Double
let deg: Int
}
private func getWeatherData(url: String, parameters: [String : String]) {
let JsonURLString:[String: Any] = ["url": WEATHER_URL, "parameters": parameters]
print(JsonURLString)
let urlString = JsonURLString["url"] as? String
guard let url = URL(string: urlString!) else { return }
URLSession.shared.dataTask(with: url) { ( data, response, err ) in
DispatchQueue.main.sync {
if let err = err {
print("Failed to get data from url:", err)
return
}
guard let data = data else { return }
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let city = try decoder.decode(WeatherData.self, from: data)
self.weatherData.description = city.weather[0].description
self.weatherData.temperature = Int(city.main.temp - 273)
self.weatherData.city = city.name
self.weatherData.condition = city.weather[0].id
self.updateUIWeatherData()
} catch {
print(error)
self.cityLabel.text = "Connection issues"
}
}
}.resume()
}
The exact error I am getting is the following:
longitude = -0.1337, latitude = 51.50998
["parameters": ["lat": "51.50998", "long": "-0.1337", "appid": "xxxxxxxxxxxxxxxxxx"], "url": "https://api.openweathermap.org/data/2.5/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))
I have looked at the following example and don't see how this would apply. Any help would be appreciated.
Icon is not appearing. Here is my model:
import UIKit
class WeatherDataModel {
//Declare your model variables here
var temperature: Int = 0
var condition: Int = 0
var city: String = ""
var weatherIconName = ""
var description: String = ""
//This method turns a condition code into the name of the weather condition image
func updateWeatherIcon(condition: Int) -> String {
switch (condition) {
case 0...300 :
return "tstorm1"
case 301...500 :
return "light_rain"
case 501...600 :
return "shower3"
case 601...700 :
return "snow4"
case 701...771 :
return "fog"
case 772...799 :
return "tstorm3"
case 800 :
return "sunny"
case 801...804 :
return "cloudy2"
case 900...903, 905...1000 :
return "tstorm3"
case 903 :
return "snow5"
case 904 :
return "sunny"
default :
return "dunno"
}
}
}
I have added my own icons. I have added this in the do catch block.
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let city = try decoder.decode(WeatherData.self, from: data)
print(city)
self.weatherData.description = city.weather[0].description
self.weatherData.temperature = Int(city.main.temp - 273)
self.weatherData.city = city.name
self.weatherData.condition = city.weather[0].id
self.weatherData.weatherIconName = WeatherDataModel.updateWeatherIcon(self.weatherData.condition)
self.updateUIWeatherData()
} catch {
print(error)
self.cityLabel.text = "Connection issues"
}
The error I am getting this error now:
Instance member 'updateWeatherIcon' cannot be used on type 'WeatherDataModel'; did you mean to use a value of this type instead?
回答1:
You are creating only the openweathermap
URL but you ignore the parameters.
Use something like this for example URLComponents
and URLQueryItem
to build the URL query properly
private func getWeatherData(parameters: [String : String]) {
guard let lat = parameters["lat"],
let long = parameters["long"],
let appID = parameters["appid"] else { print("Invalid parameters"); return }
var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/weather")!
let queryItems = [URLQueryItem(name: "lat", value: lat),
URLQueryItem(name: "lon", value: long),
URLQueryItem(name: "appid", value: appID)]
urlComponents.queryItems = queryItems
guard let url = urlComponents.url else { return }
URLSession.shared.dataTask(with: url) { ( data, response, err ) in
DispatchQueue.main.async { // never, never, never sync !!
if let err = err {
print("Failed to get data from url:", err)
return
}
guard let data = data else { return }
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let city = try decoder.decode(WeatherData.self, from: data)
print(city)
self.weatherData.description = city.weather[0].description
self.weatherData.temperature = Int(city.main.temp - 273)
self.weatherData.city = city.name
self.weatherData.condition = city.weather[0].id
self.updateUIWeatherData()
} catch {
print(error)
self.cityLabel.text = "Connection issues"
}
}
}.resume()
}
and pass only
["lat": "51.50998", "long": "-0.1337", "appid": "xxxxxxxxxxxxxxxxxx"]
as parameters.
来源:https://stackoverflow.com/questions/55891354/keynotfoundcodingkeysstringvalue-coord-intvalue-nil