Reputation: 29
I have read topics on SO but not found an answer yet. I have been trying to use a weather api to download weather data for my app. Strangely I can run it on urls without a '?' but this url has a '?' built in. I suspect this is the problem but how do I fix it, or get it to ignore it? That is my theory anyhow. Heres the code:
struct WeatherData: Decodable {
let description: String
let temp: Double
let wind: Double
}
func weather() {
let url = "http://api.openweathermap.org/data/2.5/weather?q=London,GB?&units=imperial&APPID={40b5f59a0004885043fe3df3e0b6ed8e}"
let urlObj = URL(string: url)
URLSession.shared.dataTask(with: urlObj!) {(data, response, error) in
do {
let weatherObj = try JSONDecoder().decode([WeatherData].self, from: data!)
print(data!)
for weather in weatherObj {
print(weather.temp, weather.description, weather.wind)
}
} catch {
print("Got an Error")
}
}.resume()
}
So running that as is produces the error: "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value" or the URLSession line.
Am I missing something really obvious or is there a way to fix this?
Many thanks
-- Updated: So after changing the structs and {} it was working until I began to enter data into labels. Heres the latest attempt:
func weather() {
let lat = locationManager.location!.coordinate.latitude
let long = locationManager.location!.coordinate.longitude
//let baseURL = "http://api.openweathermap.org/data/2.5/weather?"
let apiKey = "40b5f59a0004885043fe3df3e0b6ed8e"
//let weatherURL = URL(string: "\(baseURL)lat=\(lat)&lon=\(long)&units=metric&APPID=\(apiKey)")
let weahterURL = "http://api.openweathermap.org/data/2.5/weather?lat=\(lat)&lon=\(long)&units=metric&APPID=\(apiKey)"
//let url = "http://api.openweathermap.org/data/2.5/weather?q=London,GB?&units=imperial&APPID=40b5f59a0004885043fe3df3e0b6ed8e"
let urlObj = URL(string: weahterURL)
URLSession.shared.dataTask(with: urlObj!) {(data, response, error) in
do {
let weatherObj = try JSONDecoder().decode(WeatherData.self, from: data!)
print(weatherObj)
//seems as though not gettign any data from beyond this point
var desc = weatherObj.weather
var wind = weatherObj.wind.speed
var tempMin = weatherObj.main.temp_min
var tempMax = weatherObj.main.temp_max
DispatchQueue.main.async {
self.weatherDesc = desc
self.weartherWind.text = wind
self.tempMinTxt.text = tempMin
self.tempMaxTxt.text = tempMax
}
} catch {
print("Got an Error", error.localizedDescription)
}
}.resume()
}
Upvotes: 0
Views: 102
Reputation: 100503
You mistakenly construct the url instead of
let url = "http://api.openweathermap.org/data/2.5/weather?q=London,GB?&units=imperial&APPID={40b5f59a0004885043fe3df3e0b6ed8e}"
do
let url = "http://api.openweathermap.org/data/2.5/weather?q=London,GB?&units=imperial&APPID=40b5f59a0004885043fe3df3e0b6ed8e"
This
{40b5f59a0004885043fe3df3e0b6ed8e}
should be
40b5f59a0004885043fe3df3e0b6ed8e
Also the struct you create for the decoder is not valid and won't get the data
//
struct WeatherData: Decodable {
let weather: [WeatherItem]
let wind: WindItem
let main : MainItem
}
//
struct WeatherItem: Decodable {
let description: String
}
//
struct WindItem: Decodable {
let speed: Double
let deg: Double
}
//
struct MainItem : Decodable {
let tempMin: Double
let tempMax: Double
private enum CodingKeys: String, CodingKey {
case tempMin = "temp_min" , tempMax = "temp_max"
}
}
//
let weatherObj = try JSONDecoder().decode(WeatherData.self, from: data!)
Upvotes: 2