Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling NSURLSessionDownloadTask failure

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?

like image 837
dariaa Avatar asked May 07 '14 09:05

dariaa


4 Answers

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!

like image 50
Julius Avatar answered Oct 11 '22 09:10

Julius


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. */
like image 20
AsifHabib Avatar answered Oct 11 '22 08:10

AsifHabib


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.

like image 2
bk138 Avatar answered Oct 11 '22 09:10

bk138


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.

like image 1
Thanh-Nhon Nguyen Avatar answered Oct 11 '22 08:10

Thanh-Nhon Nguyen