6

I have an app in which I have to download a large number of files, from 400 to 900 files that are about 1GB total.

Which is the best approach to accomplish this?

  1. One NSURLSession and all task enqueued in it?
  2. One NSURLSession and enqueue tasks by packages (10 by 10 for example)?
  3. Multiple NSURLSession with different queues?

Actually I have a NSURLSession within all task (one per file) enqueued, but sometimes I get a Lost connection to background transfer service.

Here is my code:

if([[UIDevice currentDevice] isMultitaskingSupported])
{
    __block UIBackgroundTaskIdentifier bgTask;

    UIApplication *application = [UIApplication sharedApplication];

    bgTask = [application beginBackgroundTaskWithExpirationHandler:^{

        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        NSString *uuidString;
        CFUUIDRef uuid = CFUUIDCreate(nil);
        uuidString = CFBridgingRelease(CFUUIDCreateString(nil, uuid));
        CFRelease(uuid);
        //            }

        NSURLSessionConfiguration *sessionConfiguration;

        if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0"))
        {
            sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.fiveflamesmobile.bakgroundDownload"];
        }
        else
        {
            sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.fiveflamesmobile.bakgroundDownload"];
        }
        sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
        sessionConfiguration.sessionSendsLaunchEvents = YES;
        sessionConfiguration.discretionary = YES;
        sessionConfiguration.timeoutIntervalForResource = 0; //NO timeout
        sessionConfiguration.timeoutIntervalForRequest = 0; //No timeout
        sessionConfiguration.networkServiceType = NSURLNetworkServiceTypeBackground;

        self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                     delegate:self
                                                delegateQueue:nil];

        NSLog(@"##### ------- Sesion created succesfully");

        //    [self batchDownloading];

        for (id<FFDownloadFileProtocol> file in self.selectedCatalogProducto.downloadInfo.arrayFiles)
        {
            [self startDownloadFile:file];
        }

        NSLog(@"##### ------- Download tasks created successfully ------");

        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    });
}

}
tokyovariable
  • 1,656
  • 15
  • 23
Rotten
  • 742
  • 10
  • 24
  • `One NSURLSession and enqueue tasks by packages (10 by 10 for example)?` sounds good. – Anoop Vaidya Nov 21 '14 at 13:19
  • @AnoopVaidya why do you say that? He should just create single background session and add his download tasks to that. I see no value in the 10x10 approach. – Rob Nov 21 '14 at 13:45
  • were you able to download all files in background? – MD. Jun 03 '16 at 15:06

1 Answers1

1

One NSURLSession - because you only want to handle session based things just once (auth for example).

One NSOperationQueue - with multiple operations running at the same time. (See property operationCount). It might be a little tricky implementing a NSOperation for the first time, but I'm sure this would be your best bet. https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperationQueue_class/index.html

http://nshipster.com/nsoperation/

Oh and by the way, this is a highly object oriented approach, which is always nice =)

fabianfett
  • 709
  • 7
  • 15
  • 3
    No, no, no! I'm a huge fan of wrapping network requests in `NSOperation`, but this is the one and only scenario where you definitely do _not_ to do that. A background session configuration is one where the requests continue to run long after the app is terminated and after the `NSOperationQueue` and its associated `NSOperation` objects have been destroyed. Plus, unlike standard session configuration objects, where having `maxConcurrentOperationCount` offers real value, here it just gets in the way. With background sessions, you want to instantiate all of the download requests immediately! – Rob Nov 21 '14 at 22:48
  • Okay, that's makes a lot of sense. That way even if the app is suspended the network request should continue to load. Right? Sadly though, because of that one would have need to have two different ways of implementing the download. The operation way would only work with a background session, right? – fabianfett Nov 22 '14 at 09:27
  • The background tasks continue to run not only when the app is suspended, but even after the app is completely terminated (e.g. if OS jettisons it due to memory pressure). The only thing that the background daemon knows about are the tasks, and any operation queue (and anything pending on the queue) will be long gone. So operation queue is fabulous for foreground sessions, but will only interfere with background sessions. So the "operation way would only work with" _non-background_ (i.e. default or ephemeral) sessions. (I assume that's what you meant to say. Lol.) – Rob Nov 22 '14 at 10:02