Tutorial: How To Use iOS NSURLConnection By Example

Most of the apps you’ll build will have to fetch some sort of data through the network whether it’s as simple as high scores, a configuration file or more complex data such as a large movie catalogue.

While there are a few ways you could fetch data in your iPhone application and more than a few networking libraries you could integrate, it’s still an asset to understand this handy class, NSURLConnection, since the libraries you’re using are probably using NSURLConnection under the hood. In the future, I hope to cover some of the networking libraries out there!


ARTICLE CONTENTS
1. An Asynchronous Example
2. A Synchronous Example
3. Performing a POST request
4. Example With Connection Timeout
5. Cache Policies


1. An Asynchronous Example

To fetch some data, we’ll follow these 3 basic steps:

1. Have our class conform to the NSURLConnectionDelegate protocol and declare a var to store the response data
2. Implement the NSURLConnectionDelegate protocol methods
3. Create an instance of NSURLRequest and NSURLConnection to kick off the request

The idea is that when you kick off the request in Step 3, you want to be notified of certain events that will happen, such as when the response comes back. And you’ll be handling such events via methods you implement in Step 2. In Step 1, you’re basically telling the system that you intend handle those NSURLConnection events.

Step 1.
In the class you’ll be using NSURLConnection, specify in the header file that it conforms to the NSURLConnectionDelegate protocol. Also declare an instance variable to hold the response data.

@interface ViewController : UIViewController<NSURLConnectionDelegate>
{
    NSMutableData *_responseData;
}

Step 2.
Next, in the implementation file, you’ll implement the NSURLConnection protocol methods. In the comments in the code block below, you can see what each protocol method is used for:

#pragma mark NSURLConnection Delegate Methods

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    // A response has been received, this is where we initialize the instance var you created
    // so that we can append data to it in the didReceiveData method
    // Furthermore, this method is called each time there is a redirect so reinitializing it
    // also serves to clear it
    _responseData = [[NSMutableData alloc] init];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    // Append the new data to the instance variable you declared
    [_responseData appendData:data];
}

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse*)cachedResponse {
    // Return nil to indicate not necessary to store a cached response for this connection 
    return nil;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    // The request is complete and data has been received
    // You can parse the stuff in your instance variable now
    
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    // The request has failed for some reason!
    // Check the error var
}

Step 3.
Now you’re finally ready to perform the asynchronous request. Create an instance of NSURLRequest, assign it the URL. Next, create an instance of a NSURLConnection and call the initWithRequest method, passing in your NSURLRequest.

// Create the request.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://google.com"]];

// Create url connection and fire request
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];

Step 4.
What should happen is when your request is fired in Step 3, your handler, connection:didReceiveResponse will be hit first, indicating that the server has responded. Then the handler, connection:didReceiveData: will be hit several times. This is where you’ll append the latest data to the response data variable you declared in Step 1. Then finally, connectionDidFinishLoading: will be hit and you can parse the response data variable.

If you want to do a synchronous request, you can use the sendSynchronousRequest method of NSURLConnection.

2. A Synchronous Example

A synchronous request looks like the below:

// Send a synchronous request
NSURLRequest * urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://google.com"]];
NSURLResponse * response = nil;
NSError * error = nil;
NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest
                                          returningResponse:&response
                                                      error:&error];
    
if (error == nil)
{
    // Parse data here
}

A NSURLRequest is still required. The NSURLResponse and NSError vars are passed into the sendSynchronousReqeust method so when it returns, they will be populated with the raw response and error (if any). If you need to check for stuff like response codes you can do so via the “response” variable you pass in Line 6.

In Line 5, the request will be performed synchronously and the results assigned to the NSData variable. Before you work with the data, you should check that the error variable you passed in is still nil.

Async or Sync?
So should you perform an asynchronous request or use a synchronous one for your application? I find that in the large majority of times, I’m using the async request because otherwise the UI would be frozen while the synchronous request is doing its thing and that’s a big problem when the user is performing gestures or touches and the screen is unresponsive. Unless I’m firing off a request to do something really simple and quick like ping a server, I default to using the async pattern.

3. Performing a POST Request

To POST data, all you need to do is to use NSURLRequest like we did before previously, but this time you’ll set the HTTPMethod property to POST and you’ll assign the header fields and value in the body. Then we send it with NSURLConnection like before. The only difference is that this time, we’ll use an instance of NSMutableURLRequest because we need to modify and set it’s properties after initialization.

// Create the request.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://google.com"]];
    
// Specify that it will be a POST request
request.HTTPMethod = @"POST";
    
// This is how we set header fields
[request setValue:@"application/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];

// Convert your data and set your request's HTTPBody property
NSString *stringData = @"some data";
NSData *requestBodyData = [stringData dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody = requestBodyData;
    
// Create url connection and fire request
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];

4. Example With Connection Timeout

If you want to set a timeout for your data retrieval, you can set the timeoutInterval property of your NSURLRequest. If you’re getting an error in XCode, ensure that you’re using an instance of NSMutableURLRequest because NSURLRequest is immutable.

// Setting a timeout
request.timeoutInterval = 20.0;

5. Cache Policies

To specify how your data should be cached locally, you can set a cache policy with your NSURLRequest. For example, the following snippet shows you how you can define a cache policy and a timeout.

// Initialize a request with an url cache policy and timeout.
NSURL *url = [NSURL URLWithString:@"http://google.com"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
                                                cachePolicy:NSURLCacheStorageNotAllowed
                                            timeoutInterval:20.0];

If you don’t specify any caching policy with your NSURLRequest, then it will try to conform to whatever the protocol states. For example, with HTTP it will look at the server response headers and try to conform to what it dictates about caching. For more examples and information about NSURLConnection and caching, read my post on preventing caching problems with NSURLConnection.

76 Comments

  1. Great tutorial

    I would like to do the same to this method, how can I do this? After I call NSURLConnection, I would like to split the reply into methods, that is called when NSURLConnection is done….just like you do (I am VERY new to IOS development)

    -(void) ControlDigitalPortOnSparkCore:(NSString*)MethodName :(NSString*)Command

    {
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@”https://api.spark.io/v1/devices/%@/%@”, deviceID, MethodName]];

    NSMutableURLRequest *postRequest = [NSMutableURLRequest requestWithURL: url cachePolicy: NSURLRequestReloadIgnoringCacheData timeoutInterval: 60.0];

    [postRequest setValue:@”application/x-www-form-urlencoded” forHTTPHeaderField:@”Content-Type”];

    [postRequest setHTTPMethod:@”POST”];

    NSString *bodyData = [NSString stringWithFormat:@”access_token=%@&params=%@”, token, Command];

    [postRequest setHTTPBody:[NSData dataWithBytes:[bodyData UTF8String] length:strlen([bodyData UTF8String])]];

    [NSURLConnection sendAsynchronousRequest:postRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
    {

    if (!connectionError)
    {
    //self.Result.text = [[NSString alloc] initWithBytes:data.bytes length:data.length encoding:NSUTF8StringEncoding];

    NSDictionary *retData = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&connectionError];

    NSNumber *val = [retData objectForKey:@”return_value”];

    self.Result.text = [NSString stringWithFormat:@”%@”, val];
    }
    else
    {
    self.Result.text = [NSString stringWithFormat:@”%@”,connectionError];
    }
    }];
    }

    Reply
  2. Hi Chris ,

    This is suthan first of all thanks for your valuable blogs.
    Its really helpful for me to understand the flow of connections.

    I need to ask one questions in this time , while using post method i’m getting the crash in “HttpMethod” , do you have any idea about this chris ??

    Warm regards ,
    Suthan M

    Reply
  3. I’ve been using the Hpple code on github to parse my XML and it works but it gets it asynchronously and I’m trying to get it synchronously with this. But I’m not sure where to put part3, i just need the html data in NSData, any thoughs

    Reply
  4. Thanks Chris. A question on “Part 3. Performing a Post Request.” XCode – Version 5.1 (5B130a), created an iPad app.

    In order to get the URLRequest to fire I had to change the NSURLRequest line 2 to: NSMutableURLRequest *request = [NSURLMutableURLRequest . . . . . . . . . . . Otherwise I would get ‘NSInvalidArgumentException’ error on execution.

    I’m using the same .PHP script to receive the POST as the html form page uses, however there is no data received for the entry from my app. My request, stringData, HTTPMethod and HTTPBody all return NSLog content.

    my sql insert is:
    $sql=”INSERT INTO users (FirstName, LastName, password, repNumber) VALUES (‘$_POST[FirstName]’,’$_POST[LastName]’,’$_POST[password]’,’$_POST[repNumber]’)”;

    any thoughts?

    Reply
    • Hey Phil, in step 3, that code goes into whatever method where you want to kick off the request! If you want to trigger the request upon view load then put it in “viewDidLoad” or put it in some other method if you want to trigger it when that method is called.

      Thanks for reading!

      Reply
  5. I am making a program that has a login thing, it has the NSTextFeild, and NSSecureTextFeild, or UserName and password. And i was wondering how i’d get the response back in an if statement, so i can see if the username or password were wrong or correct.

    Reply
  6. Thanks for taking the time to write this tutorial/example, as a newbie to coding cocoa its great to have an easy to follow along tutorial, thumbs up

    Reply
  7. This line : _responseData = [[NSMutableData alloc] init]; will cause memory issue as didReceiveResponse can be called multiple times during a request. As per : https://developer.apple.com/documentation/foundation/url_loading_system , – (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ // This method is called when the server has determined that it // has enough information to create the NSURLResponse object. // It can be called multiple times, for example in the case of a // redirect, so each time we reset the data. // receivedData is an instance variable declared elsewhere. [receivedData setLength:0];}

    Reply
  8. from your tutorial of NSUrlConnection connectiondidreceivedata recieving data I want to calculate it in Progress View for Recieved data is measured in data length total data I want to calculate in Progress View to display it here I enclosed of my project to download a image

    Reply
  9. hai chris from this Connectiondidrecievedata I am downloading a image , in this thread data how to set the progress view for recieved data and how to calculate the total data before recieving it since I need to show in the ProgressView in here

    Reply
  10. Hey Chris your tutorial about NSUrlConnection is not working in my xcode 4.3.2 when the conn is initialized its not hits the didrecieveresponse method please help me in this I want to dowmload a image using NSUrlConnection here i enclosed the screenshot

    Reply
  11. A great tutorial and really easy to follow. I found that instead of using the instance method in Step 3:

    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];

    That the class method:

    [NSURLConnection connectionWithRequest:request delegate:self];

    Avoids the warnings that arise from an unused variable.

    Reply
  12. Hi Chris..
    i saw lot of article bt i did’t get like ur article..in ur article explanation is nice …
    so when ever i feel difficulty i use to search ur article..
    thanks..

    Reply
  13. This its a great tutorial but for some reason i cant make it work my code :(! i’ll appreciate if you can post the source code using all the stuff you explain here! thanks a lot!! Hello from Venezuela

    Reply
  14. Hi,

    Thanks a lot for the very simple and straightforward tutorial. It helped a lot.

    There’s just 1 thing I’m unsure of that you didn’t really address. Let’s say you want to POST a few fields (like userName and userPassword). How would you go about doing so?

    Reply
    • It stripped my code but basically you need both of these protocols: NSURLConnectionDelegate,NSURLConnectionDataDelegate

      Reply
  15. Why are you splitting this into two lines:
    NSURLConnection *conn = [[NSURLConnection alloc] init];
    (void)[conn initWithRequest:request delegate:self];

    ** This is not good practice or style, this should be:

    NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];

    Reply
      • You have the error again:

        // Create url connection and fire request
        NSURLConnection *conn = [[NSURLConnection alloc] init];
        (void)[conn initWithRequest:request delegate:self];

        Normally, I wouldn’t care but because people are coming here to learn I want to make sure they are seeing the correct way to do it.

        Anything that starts with init is an initializer and so you are basically initializing things twice.

        Reply
        • Made the 2nd correction.
          You’re absolutely right, the old code was initializing the object twice. I’m quite embarrassed to miss it so thank you for catching it.

          Reply
          • Maybe this is also right?
            [NSURLConnection connectionWithRequest:request delegate:self];
            You don’t have to allocate or initialize anything. You just want to fire the connection.

Leave a Comment

69 Shares
Share
Tweet
Pin
Share
Buffer