iOS NSURLSession Example (HTTP GET, POST, Background Downlads )

In iOS NSURLSession Example, I have explained how use NSURLSession API to make HTTP requests.NSURLSession class is introduced in iOS 7 and OS X v10.9. NSURLSession is  replacement for NSURLConnection and this API gives your app the ability to perform background downloads when your app is in background.

NSURLConnection   iOS NSURLSession Example

Left images explains how NSURLConnection Works, and right image explains how NSURLSession works.

Below topics are covered in this tutorial.

1).Session Types
2).NSURLSession Task & Delegates
3).HTTP GET and POST with NSURLSessionDataTask
4).File Download with NSURLSessionDownloadTask
5).File Download when app is in background

iOS NSURLSession Example Source

1). NSURLSession Session Types

NSURLSession has three types of Sessions.
a). Default session:
The shared session uses the global singleton credential, cache and cookie storage objects. This can be used in place of existing code that uses +[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]

b). Ephemeral session
An ephemeral session has no persistent disk storage for cookies,cache or credentials, they are stored in RAM and purged automatically when the session is invalided.

c). Background session
Background session is similar to Default session, But it can be used to perform networking operations on behalf of a suspended application, within certain constraints.

//Default session
+ (NSURLSessionConfiguration *)defaultSessionConfiguration;

//Ephemeral
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;

//Background 
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier;

2). NSURLSession Tasks and Delegates

Below image explains types of NSURLSession Tasks and their hierarchy.

NSURLSession Tasks

Tasks are created in two ways. If you use the system provided delegate method, you must provide a completion handler block that returns data to your app when a transfer finishes successfully or with an error.  if you provide  custom delegate objects, the task objects call those delegates’ methods with data as it is received from the server

2.1).NSURLSessionDataTask
Data tasks exchange data using NSData. NSURLSessionDataTask is not supported in Background Sessions.

2.1.1) Create Data task with system provided Delegate methods.

 /* Creates a data task with the given request.  The request may have a body stream. */
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;

/* Creates a data task to retrieve the contents of the given URL. */
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;

When you are using the above API, you need to implement NSURLSessionDataDelegate methods.

/* The task has received a response and no further messages will be
 * received until the completion block is called. The disposition
 * allows you to cancel a request or to turn a data task into a
 * download task. This delegate message is optional - if you do not
 * implement it, you can get the response as a property of the task.
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
    completionHandler(NSURLSessionResponseAllow);
}

/* Sent when data is available for the delegate to consume.  It is
 * assumed that the delegate will retain and not copy the data.  As
 * the data may be dis-contiguous, you should use 
 * [NSData enumerateByteRangesUsingBlock:] to access it.
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
    //data: response from the server.
}

2.1.2) Create Data task with custom Delegate methods.

/*
 * data task convenience methods.  These methods create tasks that
 * bypass the normal delegate calls for response and data delivery,
 * and provide a simple cancelable asynchronous interface to receiving
 * data.  Errors will be returned in the NSURLErrorDomain, 
 * see <Foundation/NSURLError.h>.  The delegate, if any, will still be
 * called for authentication challenges.
 */
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;

 

 

2.2).NSURLSessionDownloadTask
NSURLSessionDownloadTask directly writes the response data to a temporary file. It supports background downloads when the app is not running.

2.2.1) Create Download Task with system provided delegate methods.

/* Creates a download task with the given request. */
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request;

/* Creates a download task to download the contents of the given URL. */
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url;

/* Creates a download task with the resume data.  If the download cannot be successfully resumed, URLSession:task:didCompleteWithError: will be called. */
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;

 

If you are using  the above API, You need to implement NSURLSessionDownloadDelegate methods

/* 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.
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                              didFinishDownloadingToURL:(NSURL *)location;

/* Sent periodically to notify the delegate of download progress. */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                           didWriteData:(int64_t)bytesWritten
                                      totalBytesWritten:(int64_t)totalBytesWritten
                              totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;

/* Sent when a download has been resumed. If a download failed with an
 * error, the -userInfo dictionary of the error will contain an
 * NSURLSessionDownloadTaskResumeData key, whose value is the resume
 * data. 
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                      didResumeAtOffset:(int64_t)fileOffset
                                     expectedTotalBytes:(int64_t)expectedTotalBytes;

 

2.2.2) Create Download Task with custom delegate methods.

/*
 * download task convenience methods.  When a download successfully
 * completes, the NSURL will point to a file that must be read or
 * copied during the invocation of the completion routine.  The file
 * will be removed automatically.
 */
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData completionHandler:(void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler;

 

 

2.3).NSURLSessionUploadTask
Upload Task sends data/file and it supports background uploads when the app is not running.

2.3.1) Create Upload task with system provided delegate methods.

/* Creates an upload task with the given request.  The body of the request will be created from the file referenced by fileURL */
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;

/* Creates an upload task with the given request.  The body of the request is provided from the bodyData. */
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData;

/* Creates an upload task with the given request.  The previously set body stream of the request (if any) is ignored and the URLSession:task:needNewBodyStream: delegate will be called when the body payload is required. */
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request;

 

If you are using the above API, you need to implement below NSURLSessionTaskDelegate method.

Note: NSURLSessionUploadTask is not having any special delegate class.  Delegate method is in NSURLSessionTaskDelegate

 

/* Sent periodically to notify the delegate of upload progress.  This
 * information is also available as properties of the task.
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                                didSendBodyData:(int64_t)bytesSent
                                 totalBytesSent:(int64_t)totalBytesSent
                       totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend;

 

2.3.2) Create Upload Task with custom delegate methods.

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;

 

3).HTTP GET and POST with NSURLSessionDataTask

In this section, I have explained how to send HTTP GET/POST requests using NSURLSessionDataTask.

You need to follow the below steps for NSURLSession.

a) Create Session Configuration

b) Create a NSURLSession Object.

c) Create a NSURLSession Task ( Data,Download or Upload)

d) If you want to use system delegate methods, you need to implement them in your class.

e) Start the task by calling [resume] method.

 

3.1 HTP GET with Custom delegate method.

-(void) sendHTTPGet
{
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];

    NSURL * url = [NSURL URLWithString:@"http://hayageek.com/"];

    NSURLSessionDataTask * dataTask = [defaultSession dataTaskWithURL:url
                                                         completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if(error == nil)
        {
            NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
            NSLog(@"Data = %@",text);
        }

    }];

    [dataTask resume];

}

3.2).HTTP POST with Custom delegate method.

-(void) httpPostWithCustomDelegate
{
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];

    NSURL * url = [NSURL URLWithString:@"http://hayageek.com/examples/jquery/ajax-post/ajax-post.php"];
    NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
    NSString * params =@"name=Ravi&loc=India&age=31&submit=true";
    [urlRequest setHTTPMethod:@"POST"];
    [urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];

    NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
                                        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                          NSLog(@"Response:%@ %@\n", response, error);
                                          if(error == nil)
                                          {
                                              NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
                                              NSLog(@"Data = %@",text);
                                          }

                                      }];
    [dataTask resume];

}

3.3).HTTP POST with system provided delegate methods.

When you want use system provided delegate methods, you need to implement NSURLSessionDataDelegate methods.

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
    NSLog(@"### handler 1");

    completionHandler(NSURLSessionResponseAllow);
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
     NSString * str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"Received String %@",str);
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
    if(error == nil)
    {
        NSLog(@"Download is Succesfull");
    }
    else
        NSLog(@"Error %@",[error userInfo]);
}

Below is the code for sending HTTP Post Request.

-(void) sendHTTPPost
{
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];

    NSURL * url = [NSURL URLWithString:@"http://hayageek.com/examples/jquery/ajax-post/ajax-post.php"];
    NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
    NSString * params =@"name=Ravi&loc=India&age=31&submit=true";
    [urlRequest setHTTPMethod:@"POST"];
    [urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];

    NSURLSessionDataTask * dataTask = [defaultSession dataTaskWithRequest:urlRequest];
    [dataTask resume];

}

4).File Download with NSURLSessionDownloadTask

In this section, I have explained how to download files using NSURLSessionDownloadTask.

4.1). File Download with custom delegate method.

-(void) downloadFile
{
    NSURL * url = [NSURL URLWithString:@"https://s3.amazonaws.com/hayageek/downloads/SimpleBackgroundFetch.zip"];

    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];

    NSURLSessionDownloadTask * downloadTask =[ defaultSession downloadTaskWithURL:url
                                                                     completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error)
    {
        if(error == nil)
        {
            NSLog(@"Temporary file =%@",location);

            NSError *err = nil;
            NSFileManager *fileManager = [NSFileManager defaultManager];
            NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

            NSURL *docsDirURL = [NSURL fileURLWithPath:[docsDir stringByAppendingPathComponent:@"out.zip"]];
            if ([fileManager moveItemAtURL:location
                                     toURL:docsDirURL
                                     error: &err])
            {
                NSLog(@"File is saved to =%@",docsDir);
            }
            else
            {
                NSLog(@"failed to move: %@",[err userInfo]);
            }

        }

    }];
    [downloadTask resume];

}

If you want to get download progress you need to use system provided delegate methods.

 

4.1). File Download with system provided delegate method.

You need to implement  NSURLSessionDownloadDelegate methods.

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    NSLog(@"Temporary File :%@\n", location);
    NSError *err = nil;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

    NSURL *docsDirURL = [NSURL fileURLWithPath:[docsDir stringByAppendingPathComponent:@"out1.zip"]];
    if ([fileManager moveItemAtURL:location
                             toURL:docsDirURL
                             error: &err])
    {
        NSLog(@"File is saved to =%@",docsDir);
    }
    else
    {
        NSLog(@"failed to move: %@",[err userInfo]);
    }

}

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    //You can get progress here
    NSLog(@"Received: %lld bytes (Downloaded: %lld bytes)  Expected: %lld bytes.\n",
          bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
}

Below code downloads the file.

-(void) downloadFileWithProgress
{
    NSURL * url = [NSURL URLWithString:@"https://s3.amazonaws.com/hayageek/downloads/SimpleBackgroundFetch.zip"];
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];

    NSURLSessionDownloadTask * downloadTask =[ defaultSession downloadTaskWithURL:url];
    [downloadTask resume];

}

5). File Download when app is in background

To download data when the app is in background, you need to use NSURLSession’s background session. Below code explains how to create background task.

-(void) backgroundDownloadTask
{
    NSURL * url = [NSURL URLWithString:@"http://www.hdwallpapersinn.com/wp-content/uploads/2012/09/HD-Wallpaper-1920x1080.jpg"];
    NSURLSessionConfiguration * backgroundConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:@"backgroundtask1"];

    NSURLSession *backgroundSeesion = [NSURLSession sessionWithConfiguration: backgroundConfig delegate:self delegateQueue: [NSOperationQueue mainQueue]];

    NSURLSessionDownloadTask * downloadTask =[ backgroundSeesion downloadTaskWithURL:url];
    [downloadTask resume];

}

In iOS, when a background transfer completes , iOS  relaunches your app in the background and calls the application:handleEventsForBackgroundURLSession:completionHandler: method on your app’s UIApplicationDelegate object. You need to store that completionHandler. You can use the argument identifier to rejoin the background session.

when the session finishes the last background download task, it sends the session delegate a URLSessionDidFinishEventsForBackgroundURLSession: message. Your session delegate should then call the stored completion handler.

1).Add handleEventsForBackgroundURLSession() delegate method in your AppDelegate class.

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
    NSLog(@"Save completionHandler");
    self.completionHandler = completionHandler;

}

2).add URLSessionDidFinishEventsForBackgroundURLSession() delegate in NSURLSessionDelegate class.

-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
    NSLog(@"Background URL session %@ finished events.\n", session);

    AppDelegate * delegate =(AppDelegate *)[[UIApplication sharedApplication] delegate];
    if(delegate.completionHandler)
    {
        void (^handler)() = delegate.completionHandler;
        handler();
    }

}

Reference: Apple Documentation


I am a Developer. My motto: "Language is not a barrier" http://hayageek.com
All posts by Ravishanker Kusuma