Search code examples
iosjsonswiftopenweathermap

Can't get myDescription value to be shown on MainLabel, JSON API


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()
        
    }
    
}

Solution

  • 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)
            }
        }
    }