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
How to Convert Unmanaged<Cfdata> to Nsdata
Swift Seems to Be Slower as Objective-C in Loops
How to Get Rid of Array Brackets While Printing
How to Compare Result to .Succeed in Swift
Swift Radio Streaming Avplayer
Swift 3: Int Is Not Convertible to Bool in Bitwise Operation
iOS Swift - Uitableviewcell Custom Subclass Not Displaying Content
Navigationlink Is Grayed Out and Does Not Perform Any Action
See Characters in an Nscharacterset (Swift)
Get the First Day of Week Without Weekcalendarunit
Lottieanimationview Size Won't Change/Is Too Small (Ios/Swift)
How to Cast Generic Number Type 'T' to Cgfloat
Swift 3 Issue with Cvararg Being Passed Multiple Times
Opening Import File for Module 'Swift': Not a Directory
Explicitly Unwrapping Optional Nil Does Not Cause Crash
Swiftui List View Not Updating After Core Data Entity Updated in Another View