How to Return a Value from a Void Closure in Swift

How to return a value from a void closure in Swift?

Since it's an asynchronous method, you cannot return the value, but instead follow the completion handler pattern, including the data returned as a parameter:

func performAllMatchesQueryWithCompletionHandler(completionHandler: (UIBackgroundFetchResult, [GTLUserUser]?, ErrorType?) -> ()) {
let query = GTLQueryUser.queryForUserList()
query.userBucket = "messages-20-messagestabletes-1465782960"
service.executeQuery(query) { ticket, response, error in
guard error == nil else {
completionHandler(.failed, nil, error)
return
}

if let userCollection = response as? GTLUserCollection, let newUsers = userCollection.items() as? [GTLUserUser] {
completionHandler(.newData, newUsers, nil)
} else {
completionHandler(.noData, nil, nil)
}
}
}

I infer from your use of UIBackgroundFetchResult, that you're doing a background fetch. If so, your performFetchWithCompletionHandler might look like so:

func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
performAllMatchesQueryWithCompletionHandler { fetchResult, users, error in
switch fetchResult {
case .failed:
// do whatever you want if there was an error

case .noData:
// do whatever you want when there is no data

case .newData:
// do whatever you want with `users`, presumably updating your model or what have you
}

completionHandler(fetchResult)
}
}

You could then call this method from viewDidLoad or wherever appropriate for your app.

Note, I removed the leading underscore on the method names, as that's not a common convention in Swift, but call your methods whatever you want. And I renamed _getAllMatches to performAllMatchesQueryWithCompletionHandler, as it makes it more clear that you're performing an asynchronous query.


In comments, you say that you're not doing background fetch, but rather are populating a table. So you might do something like:

func retrieveDataForTableView(tableView: UITableView) {
performAllMatchesQueryWithCompletionHandler { fetchResult, users, error in
switch fetchResult {
case .failed:
// do whatever you want if there was an error

case .noData:
// do whatever you want when there is no data

case .newData:
// do whatever you want with `users`, presumably updating your model or what have you

// once you've updated your model, you can reload the table:

tableView.reloadData()
}
}
}

Note, I've assumed that this completion handler is running on the main thread. If not, you'd want to dispatch_async(dispatch_get_main_queue()) { ... } the code that updates the model and calls reloadData.

Personally, I wouldn't be inclined to use UIBackgroundFetchResult for my performAllMatchesQueryWithCompletionHandler if I wasn't really doing background fetch. I'd probably use my own enumeration for that, to avoid any confusion regarding the intent of this code.

How to capture the return value of a closure

If you wanted to do this purely with a closure (and not a function that accepts a closure), you could do something like:

let myClosure: (Int) -> String = { age in
if age < 10 {
return "You're just a baby"
}
else {
return "You can play the game"
}
}

let answer = myClosure(4) // "You're just a baby"

How to return value from a Closure in Swift?

You are correct, sendTwitterRequest will return after your function has already returned, so there is no way for the outer function to return an imageURL.

Instead, in the closure, take the return value that you want in the cell and store it somewhere (in a member variable) and have the tableView update it itself (e.g. with tableView.reloadData()).

This will cause it to get the cell again (cellForRow ...). Change the implementation to use the member variable where you stored the value from the call.

Swift. How to return a function from a closure

Closure does not support return statement. Instead use completion block inside main thread to perform the task:

i.e

function AA( completion: @escaping (Result<[Return Type], Error>) -> Void) {
localPlayer.authenticateHandler{
//…
if trigger {
DispatchQueue.main.async {
completion(//Whatever Return Value)
}
}
dosomething()
}
}

Swift get return value from closure and use it to return from closure that it's inside of

If the closure is non-escaping, this is easy:

let my_filtered_objects = my_objects.filter { obj in
var retVal = false
myClosure(obj.id) { bool in
retVal = bool
}
return retVal
}

For an escaping closure, you may need to use a semaphore to make sure the closure has finished by the time your function returns:

let my_filtered_objects = my_objects.filter { obj in
var retVal = false
let semaphore = DispathchSemaphore(value: 0)

myClosure(obj.id) { bool in
retVal = bool
semaphore.signal()
}

semaphore.wait()

return retVal
}

As @Woof said, though, using a dispatch group to do this asynchronously may be better-performing.

Add a return value to a closure

You can give the function params an @escaping callback returning an array or whatever you need;

An example of this for a network request;

class func getGenres(completionHandler: @escaping (genres: NSArray) -> ()) {
...
let task = session.dataTask(with:url) {
data, response, error in
...
resultsArray = results
completionHandler(genres: resultsArray)
}
...
task.resume()
}

Then to call it you could do something like this;

override func viewDidLoad() {
getGenres {
genres in
print("View Controller: \(genres)")
}
}


Related Topics



Leave a reply



Submit