Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting NSURLSessionDataTask into a Download task with Background support

I need to download with background ability certain files (not all of them), after checking the headers (for lenght and types), but it has to be in the same operation, not creating a new task/request (because sometimes I get an error from the server due to many connections in a short period of time). So I start the Task:

NSURLSessionConfiguration *configuratione = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *sessione = [NSURLSession sessionWithConfiguration:configuratione delegate:self delegateQueue:nil];
NSURLSessionDataTask *datatask = [sessione dataTaskWithRequest:request];
[datatask resume];

Then, I know that is possible to convert a Data Task into a Download task when receiving the first response, with this delegate:

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
    if(XXXXXXXXXX){
        NSLog(@"transform into a download");
        completionHandler(NSURLSessionResponseBecomeDownload);
    }else{
        NSLog(@"Keep loading normally");
        completionHandler(NSURLSessionResponseAllow);
    }
}

However, since Data Tasks can't use BackgroundSessionConfiguration, I suppose that the new created download will use the same Default Session Configuration. How can I keep that download running in background? Is there any way of changing it's session to a background one? Or which would be the approach?

like image 405
eiprol Avatar asked Apr 25 '14 12:04

eiprol


1 Answers

This question is kind of difficult to give a clear answer, seams to me, that all 3 major URLLoading factors (sessionType, taskType, FG/BG creation) are restricted by your designs.

Since session keeps a deep-copy on the configuration (which determines default/BackGround/Ephemeral session-nature-type), after initiating your session (in our case: your default-type-Session) you can NOT modify the configuration-Object for this current session any more. So, if your design does NOT allow making new Task associated with a new (hopefully) BG-type-Session, there is no way to only magically convert a "dataTask" into a "downloadTask".

Keep in mind, NSURLSessionDataTask and NSURLSessionDownloadTask are both subclasses of NSURLSessionTask, NSURLSessionDataTask and NSURLSessionDownloadTask handle incoming response data (piece-wise VS file-wise respectively) very differently implemented by the frameworks.

An attractive illusion can be this attractive method URLSession:dataTask:didBecomeDownloadTask: ,but you must create a new task (DownloadTask in deed) associated with the current (deeply stamped by your earlier configured default-type) session, and leave the original task (dataTask) as an orphan. My understanding is your design can NOT take this option due to extra creation of task, as well as you will have to stay with default-type session configure.

URLSession:dataTask:didBecomeDownloadTask: should really be named as URLSession:dataTask:wasReplacedByDownloadTask:

Only simple solution I have now is that, in Data-Task-Delegate (class implements NSURLSessionDataDelegate protocol) when receiving URLSession:dataTask:didReceiveData: initial call, starts storing those piece-wise data in certain way (store into a temp-file, maybe, simulating default action of NSURLSessionDownloadTask), and make sure execute this delegation asynchronously on a NSOperationQueue (I guess your "background ability" means secondary thread, which can be offered by NSOperationQueue underlining threading mechanism), until download is complete, then check your storage for accumulated results (if handle any errors and/or transfer the file elsewhere) in this general NSURLSessionTaskDelegate method "URLSession:task:didCompleteWithError:"

Doing so, you convert the request (represented by a NSURLSessionDataTask) into a download (not a NSURLSessionDownloadTask). To satisfy this converting happen on a background queue, provide a non-nil value for the (session/task) this delegate method's last parameter: -- otherwise, serial operation queue will not meet your "background ability" need

NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];

NSURLSession *sessione = [NSURLSession sessionWithConfiguration:configuratione delegate:self delegateQueue: aQueue];

Other ideas will be manually execute multiple NSOperation-objects, override their start-methods to ensure asynchronous execution for your downloading-task, that could be a bit tricky.

Any other folks, who have better solutions, please bring more sparks...or correct me for any misleadings I possibly have made.

like image 170
J-Q Avatar answered Sep 24 '22 17:09

J-Q