Downloading multiple files Using NSURLSession, and saving their progress in the background

I used NSURLSession to upload a single file and it works great. Now I need to upload three files in the background, and also manage their progress in UIProgress. My single download code is below ..

- (IBAction)startBackground:(id)sender { // Image CreativeCommons courtesy of flickr.com/charliematters NSString *url = @"http://farm3.staticflickr.com/2831/9823890176_82b4165653_b_d.jpg"; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]]; self.backgroundTask = [self.backgroundSession downloadTaskWithRequest:request]; [self setDownloadButtonsAsEnabled:NO]; self.imageView.hidden = YES; // Start the download [self.backgroundTask resume]; } - (NSURLSession *)backgroundSession { static NSURLSession *backgroundSession = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.shinobicontrols.BackgroundDownload.BackgroundSession"]; backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; }); return backgroundSession; } #pragma mark - NSURLSessionDownloadDelegate methods - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { double currentProgress = totalBytesWritten / (double)totalBytesExpectedToWrite; dispatch_async(dispatch_get_main_queue(), ^{ self.progressIndicator.hidden = NO; self.progressIndicator.progress = currentProgress; }); } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes { // Leave this for now } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { // We've successfully finished the download. Let save the file NSFileManager *fileManager = [NSFileManager defaultManager]; NSArray *URLs = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; NSURL *documentsDirectory = URLs[0]; NSURL *destinationPath = [documentsDirectory URLByAppendingPathComponent:[location lastPathComponent]]; NSError *error; // Make sure we overwrite anything that already there [fileManager removeItemAtURL:destinationPath error:NULL]; BOOL success = [fileManager copyItemAtURL:location toURL:destinationPath error:&error]; if (success) { dispatch_async(dispatch_get_main_queue(), ^{ UIImage *image = [UIImage imageWithContentsOfFile:[destinationPath path]]; self.imageView.image = image; self.imageView.contentMode = UIViewContentModeScaleAspectFill; self.imageView.hidden = NO; }); } else { NSLog(@"Couldn't copy the downloaded file"); } if(downloadTask == cancellableTask) { cancellableTask = nil; } else if (downloadTask == self.resumableTask) { self.resumableTask = nil; partialDownload = nil; } else if (session == self.backgroundSession) { self.backgroundTask = nil; // Get hold of the app delegate SCAppDelegate *appDelegate = (SCAppDelegate *)[[UIApplication sharedApplication] delegate]; if(appDelegate.backgroundURLSessionCompletionHandler) { // Need to copy the completion handler void (^handler)() = appDelegate.backgroundURLSessionCompletionHandler; appDelegate.backgroundURLSessionCompletionHandler = nil; handler(); } } } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { dispatch_async(dispatch_get_main_queue(), ^{ self.progressIndicator.hidden = YES; [self setDownloadButtonsAsEnabled:YES]; }); } 
+7
ios ios7 nsurlconnection nsurlsession
source share
1 answer

You can have multiple NSURLSessionDownloadTask using the same NSSession, and each of them runs one after another in the same mainQueue.

upon successful download, they call:

 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location 

If you download MP4 from 100 mb and pic. 10 KB, then they are returned in different orders in this method.

So, to keep track of which session and which downloadTask are back in this

you need to set the row id before you call the web service

To distinguish / track NSURLSessions , you set

 session.configuration.identifier 

to highlight NSURLSessionDownloadTask , use

 downloadTask_.taskDescription downloadTask_.taskDescription = [NSString stringWithFormat:@"%@",urlSessionConfigurationBACKGROUND_.identifier]; 

For example, in my project, I uploaded several of my favorite user videos and their thumbnails.

Each element had an identifier eg1234567 so I needed to make two calls for each loved one

so I created two identifiers

 "1234567_VIDEO" "1234567_IMAGE" 

then two ws calls are called and passed in the identifier to session.configuration.identifier

 http://my.site/getvideo/1234567 "1234567_VIDEO" http://my.site1/getimage/1234567 "1234567_IMAGE" 

iOS7 will load items in the background, the application may return to sleep mode Upon completion, it calls

 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location 

Then i get

 session.configuration.identifier "1234567_IMAGE" 

separate it and check the values

 1234567_IMAGE "1234567" "_IMAGE" > item at location is a MP4 so save as /Documents/1234567.mp4 "_VIDEO" > item at location is a jpg so save as /Documents/1234567.jpg 

If you have 3 URLs, you can have one NSURLSessionDownloadTask for NSSession

 file 1 - NSSession1 > NSURLSessionDownloadTask1 file 2 - NSSession2 > NSURLSessionDownloadTask2 file 3 - NSSession3 > NSURLSessionDownloadTask3 

It looks like the application is in the foreground. But I had problems when using BACKGROUND TRANSFER with BACKGROUND FETCH. The first NSSession> NSURLSessionDownloadTask1 will return, and then none of the others will be called.

It is safer to have multiple NSURLSessionDownloadTask in one NSSession1

 file 1 - NSSession1 > NSURLSessionDownloadTask1 file 2 - > NSURLSessionDownloadTask2 file 3 - > NSURLSessionDownloadTask3 

Be careful when making this call to NSSession finishTasksAndInvalidate not invalidateAndCancel

  //[session invalidateAndCancel]; [session finishTasksAndInvalidate]; 

invalidateAndCancel will terminate the session and not complete other load tasks

+5
source share

All Articles