Handling NSURLSessionDownloadTask failure
Asked Answered
P

5

8

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?

Priest answered 7/5, 2014 at 9:37 Comment(2)
I have noticed the same behaviour in that DidFinishDownloadingToURL is called alongside didCompleteWithError. This has caused tremendous issues for us. How have you worked around this?Roeder
location might be nill in that case. Can you check this?Birdsong
C
4

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!

Coinsure answered 3/8, 2017 at 17:49 Comment(0)
B
2

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. */
Birdsong answered 8/9, 2016 at 8:36 Comment(0)
C
2

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.

Counterplot answered 12/10, 2018 at 11:52 Comment(0)
D
1

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.

Desiccator answered 7/5, 2014 at 14:41 Comment(3)
I'd like my users to have their downloads finished when my app goes into background mode, so I can not use completion blocks instead of a delegate (since I'm using background session)Priest
I get you. So how about using a global BOOL in order to know if you've processed the response?Desiccator
Well, of course there can be a workaround, but I was going for some deeper understanding. Is it an expected behaviour or is it a bug that should be reported, etc. BTW a BOOL flag is not the best choice here, since in URLSession:downloadTask:didFinishDownloadingToURL: (which is called first) one usually copies the file to the documents directory for further processing. It would be nice to know at that point if the download finished successfully or with error.Priest
F
-1

NSURLSessionDownloadTask is a subclass of NSURLSessionTask, which has an error property. Could you check that in your URLSession:downloadTask:didFinishDownloadingToURL: delegate method before you attempt to copy your file?

Flynn answered 20/1, 2016 at 2:50 Comment(1)
The error property remains nil unless it's a client-side error.Coinsure

© 2022 - 2024 — McMap. All rights reserved.