0

I would like to set the return value equal to the value in my for loop so that I can return it from the func. Do you have an idea how to do that?

static func getStones() -> Double {
    let url = NSURL(string: "MYURL")
    let request = NSMutableURLRequest(url: url as URL!)
    var stonesNew = Double()

    let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
        let responseString = try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! NSDictionary
        let contacts = responseString["Sheet1"] as? [AnyObject]

        for contact in contacts!{
            let stones = contact["stones"] as! Double
            stonesNew = stones
        }

    }
    task.resume()
    return stonesNew
}
  • So I would like to set "stonesNew" to my downloaded "stones" but it always returns stones = 0
4
  • Tom did u mean to set stones value to stonesNew ?? Commented Apr 12, 2017 at 5:32
  • you want to return total of stones? It will always return zero. Commented Apr 12, 2017 at 5:33
  • task.resume() starts off the task and then returns. So when it finishes and you are returning stonesNew, the task has not yet completed. If you must do it this way, you need to use a semaphore to wait for the result to be returned from the server. A better approach would be to pass a handler to this function to call when the result is returned. Commented Apr 12, 2017 at 5:34
  • Look for completion handlers in swift. Very helpful incase of asynchronous tasks returning values. Commented Apr 12, 2017 at 5:34

2 Answers 2

1

The dataTask is an async task. So this function always returns the stonesNew immediately before the dataTask is completed. So the solution for an async task is completionHanlder, like this:

static func getStones(completion: @escaping (Double) -> Void)  {
    let url = NSURL(string: "MYURL")
    let request = NSMutableURLRequest(url: url as URL!)
    var stonesNew = Double()
    let task = URLSession.shared.dataTask(with: request as URLRequest) {data,response,error in

        let responseString = try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! NSDictionary
        let contacts = responseString["Sheet1"] as? [AnyObject]

        for contact in contacts!{

            let stones = contact["stones"] as! Double
            stonesNew = stones
        }

        completion(stonesNew)
    }
    task.resume()
}

And use it like this:

MyClass.getStones(completion: { (stones) in    
    print(stones)
})
Sign up to request clarification or add additional context in comments.

1 Comment

Correct me if I'm wrong but there is now way to create a reusable variable of stone for my following coding? For example if my downloaded double stones = 10.0 I would like to use this value as a normal constant for the following coding. let stonesConstant = myClass.getStones(... for example for an array: let arr = [stonesConstant]
0

You can't, because dataTask is async.

You have to refactor your code to accept the value of variables stonesNew at a later stage, see the following Playground:

import UIKit


let textField = UITextField()
// This is probably something like your code now... a function is doing something with the value of newStones
func buttonPressed() {
    textField.text = "\(getStones())"
}
// And this is your current getStones function 
func getStones() -> Double {
    // the code you have now
    return 0
}

// Let's see how we can do things with callbacks
func buttonPressedV2() {
    newGetStnes { (newStones) in
        textField.text = "\(newStones)"
    }
}

func newGetStnes(callback: (Double) -> ()) {
   let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
       // calculate newStones the way you were doing..
       // The following will call back your function, giving the result
       callback(newStones)
    }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.