1

I'm having a hard Time changing an my global array monthlyAvgArray through my parseJson() function. When I run the debugger, it shows that it has values at one point, but then when I try to access it outside the function, it says its empty. I have tried returning an array from my function and setting it equal to the global array, but that didn't work either.

Here is my global array:

//declaring the dynamic arrays that will hold the information that is parsed
//will be using the same two arrays for each plant
var dateArray = [String]()
var monthlyAvgArray = [Double]()

And here is my parseJson() that takes in a String for the URL.

func parseJson(URL_String:String) {
    let url = URL(string: EBR_String)
    //var monthlyDoubleArray = [Double]()
    // Load the URL
    URLSession.shared.dataTask(with:url!, completionHandler: {(data, response, error) in
        // If there are any errors don't try to parse it, show the error
        guard let data = data, error == nil else { print(error!); return }

        let decoder = JSONDecoder()
        do{
            let plantData = try decoder.decode([Plant].self, from: data)
            //get each plant dictionary in plantData array of plant dictionaries
            for var eachPlant in plantData {
                // check to see if any values of the 30 day avg are null
                if (eachPlant.monthlyAVG == nil)
                {
                    //set null values to 
                    eachPlant.monthlyAVG = "0"
                }
                //print(eachPlant.date)
               // print(eachPlant.monthlyAVG!)
                let monthlyDouble = NSString(string: eachPlant.monthlyAVG!).doubleValue
                let monthlyDouble2 = Double(round(100*monthlyDouble)/100)
               // monthlyDoubleArray.append(monthlyDouble2)
                self.monthlyAvgArray.append(monthlyDouble2)
                //self.dateArray.append(eachPlant.date)
                //print(monthlyDouble)
            }
            // at this point my array has values
            print(self.monthlyAvgArray)
            //print(self.dateArray)
        }
        catch let err{print(err)}
    }).resume()
    //at this point my array does not have values
    print(monthlyAvgArray)
}

And I'm calling my parseJson() function in the viewDidLoad() here:

override func viewDidLoad() {
    super.viewDidLoad()
    //Initiatte calling the items download
   // parseJson(URL_String: EBR_String)
    parseJson(URL_String: EBR_String)
    SetGraph ()

}

I did have the global arrays set to private earlier because I don't want them to be access in other View Controllers, but I do want to be be able to be access anywhere in this specific View Controller. I'm just wondering why I'm getting values in the array at one point, and then nothing afterwards. Can anyone help me out? Thanks.

Gina
  • 77
  • 1
  • 11
  • 3
    Put a breakpoint on the two `print` lines and run your app with the debugger. Notice the order of execution. You need to understand how asynchronous methods calls work. – rmaddy Feb 25 '18 at 17:07
  • Possible duplicate of https://stackoverflow.com/questions/25203556/returning-data-from-async-call-in-swift-function. – Martin R Feb 25 '18 at 17:08
  • @rmaddy I did put break points there (two of them), and I kind of understand how the debugger and asynchronous calls work, but not 100% sure – Gina Feb 25 '18 at 17:15

1 Answers1

1

Looks like the reason that the last print statement doesn't have any values is because the array is only appended to after the request completes. As the dataTask is run asynchronously you would be printing the last print statement first and then printing the one inside of the completion handler after. So the printing of an empty array before the completion block is hit and having data within the completion blocks array would be expected.

Steve
  • 921
  • 1
  • 7
  • 18
  • Ohhh! Okay I get it. Thank you! So I'm assuming that is why my array is still empty when I call it in viewDidLoad()? – Gina Feb 25 '18 at 17:45
  • 1
    Yea, so if you call to print that array in viewDidLoad before or after the parse request it will almost always be empty (I say almost bc if the asynchronous request finished quickly you could have data before the print). However if you wanted to use the data from that request I’d suggest calling a method after the success of the request that handles a filled array. – Steve Feb 25 '18 at 17:49
  • Okay so I should call a method inside the completion handler that takes in the information? – Gina Feb 25 '18 at 18:25
  • 1
    Something along those lines. Essentially you just need to notify some method that you’ve received the data and handle it. Whether that be simply handling that in the completion block. Updating the global variable. Or eliminating the global variable and passing the data to a method that uses it is up to you depending on how the rest of the application functions. Hope that helps. – Steve Feb 25 '18 at 18:55
  • 1
    Thanks a lot for your time! You helped me out a lot. – Gina Feb 25 '18 at 19:04
  • No problem happy to help. If you think my answer was helpful please mark it as the solution. Thanks. – Steve Feb 25 '18 at 21:02