Reputation: 5083
I’m trying to get data from my RestAPI, specifically i’m getting an array of integers (which are id’s from other users), i want to loop through this array and download the data from all the other customers. A simplified version of the code is show below.
func asyncFunc(completion: (something:[Int])->Void){
//Get a json Array asynchonous from my RestAPI
let jsonArray = [1,2,3,4,5]
var resultingArray:[Int] = []
for myThing in jsonArray{
anotherAsyncFunc(myThing, completion: { (somethingElse) -> Void in
resultingArray.append(somethingElse)
})
}
}
func anotherAsyncFunc(data:Int, completion: (somethingElse:Int)->Void){
//Get some more jsonData from RestApi/data
let myLoadedData:Int = data*13356
completion(somethingElse: myLoadedData)
}
How would I make my asyncFunc
return an array with all the items it has gotten from the second (inner) async request.
I have tried getting the count of the array which is first requested from the Rest Api and just “blocking” the UI thread by using a while loop too see if the “new” array has collected all the data (the count is equal to the count of the first requested array). This has 2 major disadvantages, mainly it blocks the UI thread and further more, it will fail and crash the app if the data connection gets broken while i’m getting the data from the other users (the inner async request), cause the while loop will never complete.
My question is how would I use a completion handler to return all the data that it should return without blocking the main thread and/or having to worry about badly timed data connection losses.
Upvotes: 1
Views: 101
Reputation: 437632
You can use a dispatch group notification. So create a dispatch group, enter the group for each item in the array, exit in the completion handler of the anotherAsyncFunc
asynchronous process, and then create a notification that will trigger the final completion
closure when all of the dispatch_group_enter
calls have been offset by a corresponding dispatch_group_leave
call:
func asyncFunc(completion: (something:[Int])->Void){
//Get a json Array asynchonous from my RestAPI
let jsonArray = [1,2,3,4,5]
var resultingArray:[Int] = []
let group = dispatch_group_create()
for myThing in jsonArray {
dispatch_group_enter(group)
anotherAsyncFunc(myThing) { somethingElse in
resultingArray.append(somethingElse)
dispatch_group_leave(group)
}
}
dispatch_group_notify(group, dispatch_get_main_queue()) {
completion(something: resultingArray)
}
}
Note, you will want to make sure you synchronize the updates to resultingArray
that the anotherAsyncFunc
are performing. The easiest way is to make sure that it dispatches its updates back to the main queue (if your REST API doesn't do that already).
func anotherAsyncFunc(data:Int, completion: (somethingElse:Int)->Void){
//Get some more jsonData from RestApi/data asynchronously
let myLoadedData:Int = data*13356
dispatch_async(dispatch_get_main_queue()) {
completion(somethingElse: myLoadedData)
}
}
This is just an example. You can use whatever synchronization mechanism you want, but make sure you synchronize updates on resultingArray
accordingly.
Upvotes: 2