refer:https://web.archive.org/web/20150315072521/http://kemal.co/index.php/2012/02/fetching-data-with-getpost-methods-by-using-nsurlconnection/
Today, I want to make a demonstration of fetching data from web servers by using NSURLConnection on objective-c platform. Before starting to my post, I need to give you a little brief about some http methods, GET and POST, that are going to be used in our project.
HTTP GET Method:
GET method is oftenly used as query parameters. The parameters that are going to be sent to server can be identified in request uri. You don’t need to do any other things to send data. For instance, look at Google example below:
http://www.google.com/#q=get+example&output=search
This means that there are variables q and output with respect to “get example” and search” as values . Google will make a search with the value of q and the output function is stated as “search”. Normally instead of # sign, ?(question mark) is used. However, the syntax of google is a bit different.
HTTP POST Method:
In some cases, let’s say the sending data is really huge, GET method is inefficient. Because, the data sending with GET method is restricted with 8KB.This is the situation where POST Method overcomes the problem to send a large amount of data to server. Another case can be sending username and password data to a form in a web page. Unlike GET Method, posted data is not shown on request URI, hence, there should be a FORM in the web page to post data.
If you wish to know more detailed information about http methods, take a look at here.
What are we going to do?
We are going to create an application that will demonstrate you guys to make a GET and POST request with NSURLConnection. After that, the retrieved data will be shown in UIWebView in another view. The project screenshots will be as like as below:
Now first of all create a new project on Xcode as a single view application. You may use any other of them however the project that I have started with was single view application.
Put 3 buttons onto a xib, and make the bindings related to the view controller’s header file.
Objective-c has a delegation structure which is very powerful and easy to implement without concerning what’s going on at the back-end. NSURLConnection has a delegate “NSURLConnectionDelegate”. With iOS 5 this delegate has been split to varying delegates. If you are using iOs5 right now, you need to call “NSURLConnectionDataDelegate” while using NSURLConnection. Now how will you use it?
Open your view controller’s header class. In my example it is called “ConnectionExampleViewController.h” and modify it as like as below.
#import @interface ConnectionExampleViewController : UIViewController @property (retain, nonatomic) NSURLConnection *connection; @property (retain, nonatomic) IBOutlet UIButton *btn_syncronous; @property (retain, nonatomic) IBOutlet UIButton *btn_post; @property (retain, nonatomic) IBOutlet UIButton *btn_get; @property (retain, nonatomic) NSMutableData *receivedData; /*BUTTON EVENTS*/ -(IBAction)btn_get_clicked:(id)sender; -(IBAction)btn_post_clicked:(id)sender; -(IBAction)btn_syncronous_clicked:(id)sender; @end
What we have done in here, we have created 3 buttons, 1 NSURLConnection object, and 1 NSMutableData object. One of the most important thing in here is that our view controller has implemented NSURLConnectionDataDelegate. Whenever our connection object start to fetching from a web page, if the delegate of our connection object is set to this view controller, it will call delegate methods to warn our view controller about the state of connection. Now let’s make some coding over view controller’s .m file.
First of all, I would like to implement the event methods of our buttons. Whenever we click a button it will call relevant method that we have bound to our button previously.
-(IBAction)btn_get_clicked:(id)sender{ //initialize new mutable data NSMutableData *data = [[NSMutableData alloc] init]; self.receivedData = data; [data release]; //initialize url that is going to be fetched. NSURL *url = [NSURL URLWithString:@"http://www.yahoo.com"]; //initialize a request from url NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; //initialize a connection from request NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; self.connection = connection; [connection release]; //start the connection [connection start]; } -(IBAction)btn_post_clicked:(id)sender{ //if there is a connection going on just cancel it. [self.connection cancel]; //initialize new mutable data NSMutableData *data = [[NSMutableData alloc] init]; self.receivedData = data; [data release]; //initialize url that is going to be fetched. NSURL *url = [NSURL URLWithString:@"http://www.snee.com/xml/crud/posttest.cgi"]; //initialize a request from url NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[url standardizedURL]]; //set http method [request setHTTPMethod:@"POST"]; //initialize a post data NSString *postData = [[NSString alloc] initWithString:@"fname=example&lname=example"]; //set request content type we MUST set this value. [request setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; //set post data of request [request setHTTPBody:[postData dataUsingEncoding:NSUTF8StringEncoding]]; //initialize a connection from request NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; self.connection = connection; [connection release]; //start the connection [connection start]; } -(IBAction)btn_syncronous_clicked:(id)sender{ //if there is a connection going on just cancel it. [self.connection cancel]; //initialize new mutable data NSMutableData *data = [[NSMutableData alloc] init]; self.receivedData = data; [data release]; //initialize url that is going to be fetched. NSURL *url = [NSURL URLWithString:@"http://www.engadget.com"]; //initialize a request from url NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; NSURLResponse *response = [[NSURLResponse alloc] init]; [self.receivedData appendData:[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil]]; //initialize convert the received data to string with UTF8 encoding NSString *htmlSTR = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding]; //initialize a new webviewcontroller WebViewController *controller = [[WebViewController alloc] initWithString:htmlSTR]; //show controller with navigation [self.navigationController pushViewController:controller animated:YES]; }
I will just talk about -(IBAction)btn_post_clicked:(id)sender method because the other two is just as like as this one. In addition, this method is much more complex than the others.
Now firstly, I’m trying to cancel the connection. Why? Because, think of the end-user clicked button twice in a row. Before finishing the first request, it will try to fetch for second request, however both connections will write data into same NSMutableData object. Moreover, some of the data will be lost because every time we click a button we create a new instance of NSMutableData object.
Secondly, I create url, and afterwards a request with respect to instance of url. These are the same procedures for every requests. Now in order to make a POST to a web page, we need to set the request object’s http method. Afterwards, we MUST set the content-type of our request which will be located at http header field. This means, whenever we make a request to a server, it will know what kind of data will be posted. And lastly, we set httpBody of our request that is going to be sent to server and then create connection with our request and start created connection. This procedure is always the same in every platform. It does not differ whether or not you are using java, c# and so on.
The tricky part , the delegation, comes into play at this time. The folks at Apple has created a simple way to deal with the states of connection by using delegation structure.For those who are using C#, It is actually equal to event firing. There are actually lots of delegate methods in NSURLConnectionDataDelegate however, just only 3 of them is required to be implemented in class. Those are;
/* this method might be calling more than one times according to incoming data size */ -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ [self.receivedData appendData:data]; } /* if there is an error occured, this method will be called by connection */ -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ NSLog(@"%@" , error); } /* if data is successfully received, this method will be called by connection */ -(void)connectionDidFinishLoading:(NSURLConnection *)connection{ //initialize convert the received data to string with UTF8 encoding NSString *htmlSTR = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding]; NSLog(@"%@" , htmlSTR); //initialize a new webviewcontroller WebViewController *controller = [[WebViewController alloc] initWithString:htmlSTR]; //show controller with navigation [self.navigationController pushViewController:controller animated:YES]; }
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data this method is called more than ones if the data returned by server is huge. NSURLConnection is clever enough how to split and whenever it gets any kind of data it calls this method from bound delegate class.
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error this method is called if something is abnormally going on during the connection.
-(void)connectionDidFinishLoading:(NSURLConnection *)connection this method is called when connection finishes its job successfully. All the actions after fetching data from server can be done here. In our example, we have filled our data into our object “receivedData”. Now that, we can convert our data into string with UTF8 encoding, and then pass it to our WebViewController class. WebViewController class is just a class which contains UIWebView in its xib. We call
[self.webView loadHTMLString:self.str baseURL:nil];
in order to show HTML string that came from server.
I attach my all project so that you can work on it. If you have any questions please leave me a message.
P.S: When you download and open my project, make sure that you need to change code signing from project’s build settings tab.