I have made a weather app for iOS in Swift 4, I am using the OpenWeatherMap API to parse the JSON data to the app, I have got most of the app working, where the user inputs a city, and the weather is displayed. I have the current temp, current wind speed, current humidity, and I am trying to get the current description working, but I cannot get it to display.
I want to get the MainLabel to display the current weather description, but I can't get it to work. At the top of the code is the JSON data from the API key, the description is in the Weather section. I have tried MainLabel.Weather?.Description
but it prints out the entire description, ID, Main, and Icon values. I would appreciate guidance on it.
Here are the structs I use to decode the JSON data from OpenWeatherMap API:
JSON Structs below:
import UIKit
//Below is the JSON data from the OpenWeatherMap API
struct Coordinate : Decodable {
let lat, lon : Double?
}
struct Weather : Decodable {
var id : Int?
var main, myDescription, icon : String?
enum CodingKeys : String, CodingKey {
case id = "id"
case main = "main"
case icon = "icon"
case myDescription = "description"
}
}
struct Sys : Decodable {
let type, id : Int?
let sunrise, sunset : Date?
let message : Double?
let country : String?
}
struct Main : Decodable {
let temp, tempMin, tempMax : Double?
let pressure, humidity : Int?
}
struct Wind : Decodable {
let speed : Double?
let deg : Int?
}
struct MyWeather : Decodable {
let coord : Coordinate?
let cod, visibility, id : Int?
let name : String?
let base : String?
let weather : [Weather]?
let sys : Sys?
let main : Main?
let wind : Wind?
let dt : Date?
}
View controller below:
class ViewController: UIViewController {
@IBOutlet weak var HumidityLabel: UILabel!
@IBOutlet weak var MainLabel: UILabel!
@IBOutlet weak var WindLabel: UILabel!
@IBOutlet weak var TempLabel: UILabel!
@IBOutlet weak var LocationLabel: UILabel!
//
@IBOutlet weak var userValue: UITextField!
//Assigning Labels
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
@IBAction func GoButton(_ sender: Any) {
let text: String = userValue.text!
guard let APIUrl = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=" + text + "&appid=*********APIKEY*********&units=Metric") else { return }
//API KEY
URLSession.shared.dataTask(with: APIUrl) { data, response, error in
guard let data = data else { return }
let decoder = JSONDecoder()
//Decoder
do {
let weatherData = try decoder.decode(MyWeather.self, from: data)
if (self.MainLabel != nil)
{
if let gmain = weatherData.weather?.description {
print(gmain)
DispatchQueue.main.async {
self.MainLabel.text! = String (describing: gmain)
}
}
}
if (self.LocationLabel != nil)
{
if let gmain = weatherData.name {
print(gmain)
DispatchQueue.main.async {
self.LocationLabel.text! = "Current Weather in: " + String (gmain)
}
}
}
if (self.HumidityLabel != nil)
{
if let ghumidity = weatherData.main?.humidity
{
print(ghumidity, "THIS IS HUMIDITY")
DispatchQueue.main.async {
self.HumidityLabel.text! = String (ghumidity)
}
}
}
if (self.WindLabel != nil)
{
if let gspeed = weatherData.wind?.speed {
print(gspeed, "THIS IS THE SPEED")
DispatchQueue.main.async {
self.WindLabel.text! = String(gspeed) + " mph"
}
}
}
if (self.TempLabel != nil)
{
if let ggtemp = weatherData.main?.temp {
print(ggtemp, "THIS IS THE TEMP")
DispatchQueue.main.async {
self.TempLabel.text! = String (ggtemp) + " c"
}
}
}
} catch {
print(error.localizedDescription)
}
}.resume()
}
}
Reading through your view controller code it appears that you're trying to load the value from weatherData.weather.description
into your label which would be the description of the array of Weather
objects and not the actual value you parsed from the JSON response.
Looking at the Weather
object, you're parsing the 'description' value from the JSON response into the myDescription
property on the Weather
object, and the Weather
object is placed in an array on your weatherData
object.
So you'll need to get that value from the object in the array, instead of simply printing the description of the array with the Weather
object in it.
Based on your description of the problem I believe this is what you actually want (from the GoButton
function):
if (self.MainLabel != nil)
{
// get the first weather object in the 'weatherData's weather array, and
// use the description parsed from the json and saved in the 'myDescription'
// property here...
if let gmain = weatherData.weather?.first?.myDescription {
print(gmain)
DispatchQueue.main.async {
self.MainLabel.text! = String (describing: gmain)
}
}
}