Originially I thought that if a NSURLSessionDownloadTask
finishes successfully URLSession:downloadTask:didFinishDownloadingToURL:
method will get called, if it fails for some reason - URLSession:task:didCompleteWithError:
.
It works as expected on simulator (only one of this method is called for one download task) but on device this is not the case: in case of failure both these methods are called, URLSession:downloadTask:didFinishDownloadingToURL:
being the first the one. (an both these methods pass the same task in parameters)
Is there something I am missing?
I found a solution to this problem:
To get the status code in the response header, you must first start a NSURLSessionDataTask.
This will call the following delegate method URLSession:dataTask:didReceiveResponse:completionHandler:.
In this method, you can first check the status code of the NSURLResponse parameters (by casting it to a NSHTTPURLResponse) and finally call the completion handler with either NSURLSessionResponseBecomeDownload to convert your dataTask to a downloadTask (which will behave as you would expect from a NSURLSessionDownloadTask) or NSURLSessionResponseCancel to avoid downloading some data you don't need (for example if the response's status code is 404).
Also, if you need to do something with the converted NSURLSessionDownloadTask (like storing it in an array or a dictionary or replacing the data task with the new object), it can be done in the URLSession:dataTask:didBecomeDownloadTask:
Hope this helps someone!
According to Apple's documentation under NSURLSessionDownloadDelegate
It is standard behavior.
/* Sent when a download task that has completed a download. The delegate should
* copy or move the file at the given location to a new location as it will be
* removed when the delegate message returns. URLSession:task:didCompleteWithError:
* will still be called. */
If you were doing a HTTP request, you can cast the task's response into a NSHTTPURLResponse to get the HTTP status code:
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL )location
{
NSLog(@"response is %d\n" ((NSHTTPURLResponse)downloadTask.response).statusCode);
NSLog(@"error is %@\n", [downloadTask.error localizedDescription]);
}
Apple's logic is that when you get a 404, error will still be null.
Use completion block instead of delegate:
NSURLSessionDownloadTask *mySessionDownloadTask = [myURLSession downloadTaskWithRequest:myRequest completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error)
{
dispatch_async(dispatch_get_main_queue(), ^{
if(!error)
{
// Finish loading
}
else
{
// Handle error
});
}];
Note: If you don't get the main queue, any update related to user interface will be retarded which causes unsuspected behaviors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With