iosjsonswiftswift3

Extracting data from API (JSON format) doesn't save data outside of function call


I am trying to get an array of temperatures in a given time period from an API in JSON format. I was able to retrieve the array through a completion handler but I can't save it to another variable outside the function call (one that uses completion handler). Here is my code. Please see the commented area.

class WeatherGetter {

    func getWeather(_ zip: String, startdate: String, enddate: String, completion: @escaping (([[Double]]) -> Void)) {
        // This is a pretty simple networking task, so the shared session will do.
        let session = URLSession.shared

        let string = "api address"

        let url = URL(string: string)
        var weatherRequestURL = URLRequest(url:url! as URL)
        weatherRequestURL.httpMethod = "GET"


        // The data task retrieves the data.
        let dataTask = session.dataTask(with: weatherRequestURL) {
            (data, response, error) -> Void in
            if let error = error {
                // Case 1: Error
                // We got some kind of error while trying to get data from the server.
                print("Error:\n\(error)")
            }
            else {
                // Case 2: Success
                // We got a response from the server!
                do {
                    var temps = [Double]()
                    var winds = [Double]()
                    let weather = try JSON(data: data!)
                    let conditions1 = weather["data"]
                    let conditions2 = conditions1["weather"]
                    let count = conditions2.count
                    for i in 0...count-1 {
                        let conditions3 = conditions2[i]
                        let conditions4 = conditions3["hourly"]
                        let count2 = conditions4.count
                        for j in 0...count2-1 {
                            let conditions5 = conditions4[j]
                            let tempF = conditions5["tempF"].doubleValue
                            let windspeed = conditions5["windspeedKmph"].doubleValue
                            temps.append(tempF)
                            winds.append(windspeed)
                        }
                    }
                    completion([temps, winds])
                }
                catch let jsonError as NSError {
                    // An error occurred while trying to convert the data into a Swift dictionary.
                    print("JSON error description: \(jsonError.description)")
                }
            }
        }
        // The data task is set up...launch it!
        dataTask.resume()
    }
}


I am calling this method from my view controller class. Here is the code. 

    override func viewDidLoad() {
        super.viewDidLoad()

        let weather = WeatherGetter()
        weather.getWeather("13323", startdate: "2016-10-01", enddate: "2017-04-30") { (weatherhandler: [[Double]]) in
            //It prints out the correct array here
            print(weatherhandler[0])
            weatherData = weatherhandler[0]
        }
        //Here it prints out an empty array
        print(weatherData)

    }

Solution

  • The issue is that API takes some time to return the data, when the data is return the "Completion Listener" is called and it goes inside the "getWeather" method implementation, where it prints the data of array. But when your outside print method is called the API hasn't returned the data yet. So it shows empty array. If you will try to print the data form "weatherData" object after sometime it will work.

    The best way I can suggest you is to update your UI with the data inside the "getWeather" method implementation like this:

    override func viewDidLoad() {
        super.viewDidLoad()
    
        let weather = WeatherGetter()
        weather.getWeather("13323", startdate: "2016-10-01", enddate: "2017-04-30") { (weatherhandler: [[Double]]) in
            //It prints out the correct array here
            print(weatherhandler[0])
            weatherData = weatherhandler[0]
    
           // Update your UI here.
    
        }
        //Here it prints out an empty array
        print(weatherData)
    
    }