Closures Return Value (Previously Completionblock)

Closures return value (previously completionBlock)

The plus of closures are, that you can pass everything you want. Methods or functions - it doesn't matter.

You can pass a function within the parameters and just call it.

func someFunctionThatTakesAClosure(completionClosure: () -> ()) {
// function body goes here
if(error = false) {
completionClosure()
}

}

//Call it
someFunctionThatTakesAClosure({
//Completions Stuff
println("someFunctionThatTakesAClosure")
});

Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/ch/jEUH0.l

how to use the return value in a completion handler?

You're returning the value into the productToString function but not doing anything else with it.

func productToString(num: Int,num2: Int,completion: (Int)->String){

let result = num * num2

completion(result) // <--- Your return value ends up here
}

If you want to print the result you have to return it again out of the productToString function.

func productToString(num: Int,num2: Int,completion: (Int)->String) -> String {

let result = num * num2

return completion(result)
}

Sidenote: The empty brackets that are printed are an empty tuple which is equivalent to Void in Swift.

Return object for a method inside completion block

If you want the MakeGetRequest method to return data obtained via dataTaskWithURL, you can't. That method performs an asynchronous call, which is most likely completed after the MakeGetRequest has already returned - but more generally it cannot be know in a deterministic way.

Usually asynchronous operations are handled via closures - rather than your method returning the data, you pass a closure to it, accepting the parameters which are returned in your version of the code - from the closure invoked at completion of dataTaskWithURL, you call that completion handler closure, providing the proper parameters:

class func MakeGetRequest(urlString: String, completionHandler: (data: NSData, error: NSError) -> Void) -> Void
{
let url = NSURL(string: urlString)
var dataResponse: NSData
var err: NSError

let task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in
completionHandler(data: data, error: error)
})

task.resume()
}

Swift 5 update:

class func makeGetRequest(urlString: String, completionHandler: @escaping (Data?, Error?) -> Void) -> Void {
let url = URL(string: urlString)!
var dataResponse: Data
var err: NSError

let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, respone, error) -> Void in
completionHandler(data, error)
})

task.resume()
}

How to use completionHandler Closure with return in Swift?

func getSomething(callback: (Array<AnyObject>) -> ()) {
var dataTask = NSURLSessionDataTask()
dataTask = session.dataTaskWithRequest(request) { (data, response, error) in
if (error == nil) {
var callbackArray = Array<MyObject>()
let responseDict = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil) as NSDictionary
let response = responseDict.objectForKey("response_key") as NSDictionary
let array = response.objectForKey("array_key") as NSArray

for item: AnyObject in array {
var arrayItem = MyObject(dict: item as NSDictionary)
callbackArray.append(arrayItem)
}

callback(callbackArray)
} else {
// handle an error
}
}
dataTask.resume()
}

Then you could do something like:

getSomething() { (response) in
if let responseArray = response as? Array<MyObject> {
self.somethings = responseArray
}
}

How can I return value from completion block to use it in other viewController?

queryCompletionBlock is executed asynchronously so by the time print(self.kcalUnitValid) is called queryCompletionBlock wouldn't have finished its execution yet, in other words, the order in how execution happens is like below sequentially:

  • 1.- queryOperation.queryCompletionBlock(..) is called
  • 2.- print(self.kcalUnitValid) is called // prints empty
  • 3.- after some seconds the result of queryOperation.queryCompletionBlock(..) is returned

Code

What you could do it probably is this:

func KcalCloudKitData() {
// .. code omitted
queryOperation.queryCompletionBlock = {cursor, error in
if error != nil {
// .. code omitted
} else {
for value in self.allRecords {
self.kcalUnitValid.append(value.object(forKey: "KcalValidUnit") as! [String])
}

// Segue to another ViewController
// And also sending kcalUnitValid
self.performSegue(withIdentifier: "AppLoaded", sender: self.kcalUnitValid)
}
}
// .. code omitted
}

// Actually in this method is when you decide
// what data you are going to send to the AnotherViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "AppLoaded" {
let anotherViewController = segue.destination as! AnotherViewController
anotherViewController.kcalUnitValid = sender as! Array<[String]>
}
}

Resources:

Watch this video explaning async programming in Swift

swift 3 calling function with completion closure in return

You can't return from a closure. Also, note that your function is making a webservice call. When that part is encountered, the control doesn't go into the block immediately and the entire function execution will be over before the block is executed. Instead of returning a value you can add another completion block to your login function. Add another argument to your login function.

public func login(userName: String, password: String, completion: @escaping(Any)->Void)

Inside the login function, remove the return statement and do something like this

makeWebServiceCall(urlAddress: URL, requestMethod: .post, params: loginrequest, completion: { (JSON : Any) in
completion(JSON)
})

And when you call your login function all you have to do is,

login(userName: "", password:""){(response) in
print(response)
}

You'll have the data that you wanted to pass here



Related Topics



Leave a reply



Submit