iOS - Objective-C - Downloading Data using NSURLSession

Stephen Zaharuk / Wednesday, May 21, 2014

Previously, I talked about downloading data using NSURLConnection. That method works great, however, in iOS 7 Apple introduced a different way of downloading data, which also allows downloading while you're app is in the background. 

Just like we did with NSURLConnection, we first need to implement a protocol. This protocol is called: NSURLSessionDownloadDelegate and requires the following 4 selectors:

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite


-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error


-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes


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

Unlike NSURLConnection, where we generally create a connection per request, with NSURLSession, we create one session and instead have multiple tasks. 

So lets define our Session:

NSURLSessionConfiguration* config = [NSURLSessionConfiguration backgroundSessionConfiguration:@“myUniqueAppID”];
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];

What we're doing first, is creating a configuration, which will allow it to run in the background. The config needs a unique identifier specific to your app. It's good practice to use your app's bundle identifier, such as com.yourCompany.appName.

Once we have our configuration we can instantiate our session, where we pass in the reference to our delegate and what queue we want it to run on. You most like will want this to be the mainQueue.

For the purpose of this topic, we're going to just tacking downloading tasks. So, once your have the URL to the file you want to download, you can create a downloadTask via your session:

NSURLSessionDownloadTask* task = [_session downloadTaskWithRequest:request];

[task resume];

Now the way, NSURLSession works, is that it downloads your file directly to a temporary directory. So you don't need to worry about storing it. 

While its downloading though, it will notify you of how much has been downloaded, which is great for notifying your users of the download progress:

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
   CGFloat percentDone = (double)totalBytesWritten/(double)totalBytesExpectedToWrite;
   // Notify user.
}

Once the file is downloaded the following method will be called:

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
   // Either move the data from the location to a permanent location, or do something with the data at that location.
}

The last parameter of that method is the location of which the data was downloaded to. From here, you can move the file to a permanent place where you can work with it, or you can access the data and do something with it. However, that data won't stay there, so make sure you don't leave it, if you really need it. 

It's worth noting that Tasks, just like a NSURLConnection can be cancelled:

[_currentTask cancel];

And that about covers the basics of downloading a file using NSURLSession. 

I hope you found this useful!

By Stephen Zaharuk (SteveZ)