Reputation: 7426
I make few NSURLSession requests in a loop. I'd like to store results from responses in the same order as tasks are created. But since completion handler runs in a separate thread it sometimes happens that the response to the second task gets received before the response to the first task.
How to make sure that I get responses in same order as tasks are being started?
var recivedData = [String]()
for index in 0 ... urlsAsString.count-1 {
let myUrl = NSURL(string: urlsAsString[index])
var request = NSMutableURLRequest(URL: myUrl!)
// here I also set additional parameters (HTTPMethod, ...)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
responseData, response, error in
// here I handle the response
let result = ...
dispatch_async(dispatch_get_main_queue()) {
self.recivedData.append("\(result)") // save the result to array
}
}
task.resume()
}
Upvotes: 1
Views: 598
Reputation: 9148
Because you know the exact number of http requests.
You can create an array to the size of urls.count
, and then set the result in completion handler, corresponding to the index in each loop.
receivedData = [String](count: urls.count, repeatedValue: "No Data")
for (index,url) in enumerate(urls){
let url = NSURL(string: url)!
let task = NSURLSession.sharedSession().dataTaskWithURL(url){ data, response, error in
if error != nil{
self.receivedData[index] = "error: \(error.localizedDescription)"
return
}
let result = ...
dispatch_async(dispatch_get_main_queue()) {
self.recivedData[index] = "\(result)"
}
}
task.resume()
}
Upvotes: 1
Reputation: 9002
While I'd discourage behaviour that requires responses to be received in a specific order, you can collate the responses (regardless of the order they are received) into a known order.
The receivedData
array should be initialised with a capacity that matches the number of requests that will be made:
var receivedData = [String](count: urlsAsString.count, repeatedValue: "")
Then when you receive the response, since you're in a block that has access to the index
of the request you can add the response data directly into the index of the receivedData
array:
receivedData[index] = result as (String)
The full code is as follows:
var receivedData = [String](count: urlsAsString.count, repeatedValue: "")
for index in 0 ... urlsAsString.count-1 {
let myUrl = NSURL(string: urlsAsString[index])
var request = NSMutableURLRequest(URL: myUrl!)
// here I also set additional parameters (HTTPMethod, ...)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
responseData, response, error in
// here I handle the response
let result = ...
dispatch_async(dispatch_get_main_queue()) {
// Insert the result into the correct index
receivedData[index] = result
}
}
task.resume()
}
Upvotes: 1
Reputation: 1157
Actually, can not make sure the order of responses. There are two workarounds for this:
Send the requests one after another, which means send the next request after the previous response is returned. You can use ReactiveCocoa to make your codes elegant. Or use the networking library I wrote STNetTaskQueue, there is a STNetTaskChain which can handle the requests one after another.
Send the requests parallel(is what you are doing now), and use a NSDictionary to keep track on the request and response, after all requests is finished, combine the response in the original order.
Hope this helps!
Upvotes: 0