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.
Amazing tutorial , Thank you π how can it be done for HTTPS please ? π
Amazing tutorial , Thank you π How can I show the type of the data I will get please ?I think we should get a HTML , right ?
You are an amazing person. Thank you so much! Honestly I was really confused yesterday but this is exactly what I was looking for. Thank you so much, Chris!
THANK YOU VERY MUCH! very helpful, u’re awesome *thumbs up*
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=%@¶ms=%@”, 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];
}
}];
}
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
Hi Chris ,
I found one small issues in the code please note it thanks for your useful blogs π
Your 3rd Step —->>>> Performing a POST Request
Line 2) Error occurred
NSMutableURLRequest *request = [NSURLRequest requestWithURL:…
should be
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:…
Thanks for spotting that Suthan!
You are always welcome chris sorry for the delay reply..
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
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?
Hello! It’s probably because your stringData is not actually xml although your header values indicates that it is..
Try using “application/x-www-form-urlencoded;charset=utf-8” instead.
Chris, Works perfectly! Thanks a million!! Really!!
Hi Chris, thanks for your tutorials.
Where does the Step 3 code go?
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!
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.
Thank you for this material. Very useful. Pretty didatic explanation.
Hey, thanks for the tutorial!! Can you tell more about how to post an xml with the request?
Thanks in advance!
Hi,
Did you get to know how to post XML data in HTTP POST. If yes, kindly let us know. Thanks.
Crisp and clear
Thank you
Thanks for stopping by Nathan!
Excellent Article. Thumb up.
Thanks for reading Alex!!
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
Hey Lawrence, thanks for reading it! π
So much help! Thanks Chris, it got me exactly what I needed and I’m new to iOS Code, so thanks again!
Hey Joey, thanks for reading!
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];}
Nice explanation
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
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
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
Hey, can you confirm in ViewController.h that you are conforming to the protocol? (step 1) Thanks!
Awesome tutorial, very well-written and super easy to follow. Thanks man!
Thanks for taking the time to comment!
Your tutorial continues to help; thanks for taking the time to write it, post it, maintain it and answer questions!
It’s the funnest part of my day π Thanks for reading!
This is excellent! it’s easy to follow, to-the-point and very usable!!! thanks!
Thanks for reading, Rodney. I’m glad it helped. Thanks for taking the time to leave a note.
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.
Simple! Useful! Great tutorial!! Thanks Chris : )
Thanks for reading, Kisuk!
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..
Thanks for reading Rahul!
Good Tutorials, both here and on youtube. I learned a lot from you!
Thanks a lot Jake! Hope you continue to visit!
Really Helpful..
Thanks for reading, Deep!
Excellent guide thanks!
Thanks for reading!!
Thank you so much for this article! Its well written, clean formatted and to the point. Thx again! π
Thanks for reading!!
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
Great, helpful post!
Thank you charles! I really appreciate the feedback π
Thanks Chris very simple and detailed explanation of how NSUrlconnection works!!!!!!!!
Thank you! Glad to help π
very nice, but i have a question, what about if i want to cancel the request? if you could show me a simple example
Thanks a lot Chris. It’s really a valuable post. Helped me to overcome my issues with an app that I’m currently struggling with.
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?
Hi!
Apparently, in Part 3, the NSURLRequest should be an NSMutableURLRequest.
https://stackoverflow.com/questions/5168811/exception-while-adding-argument-to-nsmutableurlrequest
Excellent stuff. Well documented. Thanks for the detailed explanation Chris.
Also, this UIViewController should be UIViewController or people are going to have code completion problems. See: https://stackoverflow.com/questions/7803472/nsurlconnection-methods-no-more-available-in-ios5
Having said that, I did appreciate your sample code!
It stripped my code but basically you need both of these protocols: NSURLConnectionDelegate,NSURLConnectionDataDelegate
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];
Oops, you’re right! I’ve edited it to reflect this.
Thank you!
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.
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.
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.
Very Good Tutorial..
Thanks chris. It gave me a clear understanding about NSURLConnection.
Hi! Thanks for the Article! It gave me the quick, clean start that i needed.
Thanks, Chris!
This well-written tutorial helped my solve a bug in my app that I’ve been fighting with for months!
Rick
Thanks for your comment Rick! Makes me feel like it’s all worth it!
Hi Chris,
Thank you from me too, for the same reason!
Thank you Ri π