I am looking for a sample to send and receive http GET request in iOS. All I want to
do is handle communication in background thread such that it does not block main thread
and also want to handle http standard error code. Can anyone suggest me reference code or
example to handle http response data and handle proper memory management?
Any help will be thankful.
Two methods to achieve it:
1) NSURLCOnnection sendAsynchronousRequest method:
NSString *strURL= [NSString stringWithFormat:#"http://www.google.com/"];
NSURL *URL = [NSURL URLWithString:[strURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURLRequest *requestURL = [[NSURLRequest alloc] initWithURL:URL];
[NSURLConnection sendAsynchronousRequest:requestURL
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSLog(#"Response is:%#",[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
}];
2) Create and fire request then NSURLConnection Delegate Methods to get the response:
// 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];
#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
}
Related
When I'm using NSURLConnection to get data from my server, iOS still cache data. When requesting new data, iOS sending a new request to my server, but the files are still stored.
I'm using NSURLRequestReloadIgnoringCacheData and returning nil in connection:willCacheResponse:.
The problem is that I'm using my own caching object, and it's kind of dum to let iOS store a duplicate.
Should I ignore this or should I delete the cache somehow?
Update
Code for creating NSURLRequest:
request = [NSURLRequest requestWithURL:[NSURL URLWithString:URLString] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0];
Code for creating NSURLConnection:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
Code for NSURlConnectionDelegate:
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
return nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[recivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
if (_handler) _handler(response, error, nil);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (_handler) _handler(response, nil, recivedData);
recivedData = nil;
response = nil;
}
I'm sending to my server user detail and it is supposed to return a user id as a string,
the data received at my server bat I can get the string.
The code:
NSString *urlStr = [NSString stringWithFormat:#"url/////api/%#/%#",
[Email.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[Password.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
nil];
NSString *content = #"field1=42&field2=Hello";
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlStr]];
[request setHTTPMethod:#"GET"];
[request setHTTPBody:[content dataUsingEncoding:NSISOLatin1StringEncoding]];
[NSURLConnection connectionWithRequest:request delegate:self];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if (connection) {
NSLog(#"good conection");
[_receivedData appendData:_data];
NSString *DataString = [[NSString alloc] initWithData:_receivedData encoding:NSUTF8StringEncoding];
NSLog(#"foo1: %#", DataString);
NSLog(#"foo2: %#", _receivedData);
}
2014-01-03 22:27:57.322 App[962:70b] foo1:
2014-01-03 22:27:57.323 App[962:70b] foo2: (null)
Implement following NSURLConnection delegate to fetch data asynchronously.
- (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!
}
I am just new in IOS development. I've been trying to figure apple documentations. So I read this page:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html#//apple_ref/doc/uid/20001836-BAJEAIEE
and this is what I have done:
NSMutableData *testFileType;
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
testFileType = [[NSMutableData data] retain];
NSLog(#"the connection is successful");
} else {
// Inform the user that the connection failed.
NSLog(#"the connection is unsuccessful");
}
[testFileType setLength:0];
[testFileType appendData:[NSMutableData data]];
Can anyone tell me what am I missing here?
Just creating the NSURLConnection is not enough. You also need to implement the didReceiveResponse and didFinishLoading delegate methods. Without these the connection downloads the file, but you never get to see it.
NSURLConnection sends a didReceiveResponse for every redirection when the headers are received. Then it sends a didReceiveData with some bytes of the file. Those you need to append to your mutable data. Finally you get a didFinishLoading where you know that you have gotten all data. In case of error you get a didFailWithError instead.
Look at the NSURLConnectionDelegate protocol documentation: https://developer.apple.com/library/mac/ipad/#documentation/Foundation/Reference/NSURLConnectionDelegate_Protocol/Reference/Reference.html
you should implement the following delegate methods:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Error: %d %#", [error code], [error localizedDescription]);
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
responseData = [NSMutableData data];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[responseData writeToFile:savePath atomically:YES];
}
here responseData and savePath are instance variables declared with:
NSMutableData *responseData;
NSString *savePath;
and your class must conforms the NSURLConnectionDataDelegate and NSURLConnectionDelegate protocols.
For the code to work you probably want to set savePath to a working path like this
NSString *savePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"testfile.txt"];
after the download have finished, you can do anything to the file at savePath as you wish.
I am new to iOS and working on an app which runs on a real device (iPad). So, when I launch my app on the iPad after the view is visible, the app should be able poll a web server or something (without any user interaction) and get some information over HTTP and based on this information, I want fill some text fields in the app view. can you let me know if it is possible to do something like this in iOS? if so how and some sample pieces of code would be much appreciated.
Thanks.
You can download information over http using NSURLConnection in the viewWillAppear or viewDidLoad. After download the data if its XML parse using NSXMLParser (or any other XML parser for iOS).
//Lets say you have download and process method
- (void)downloadAndProcess
{
//URL you want to download Info from
NSURL* url = [NSURL URLWithString:#"http://google.com"];
//Make a mutable url request
NSMutableURLRequest* req = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60];
NSURLConnection* conn = [NSURLConnection connectionWithRequest:req delegate:self];
if(conn)
{
//NSMutableData receivedData is an instance variable
receivedData = [[NSMutableData alloc] init];
}
}
//NSURLConnection Delegate methods here
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Error downloading data :%#",[error localizedDescription]);
// release receivedData object when connection fails
[receivedData release],receivedData = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Connection did finish downloading data which you can process based on what your data is
// release receivedData object once you are done processing it.
[receivedData release],receivedData = nil;
}
I can successfully retrieve data asynchronously through NSURLConnection from any other part in the code base except in the canDrawMapRect function in my subclassed TileOverlayView class.
I'm modifying the MapKit sample called tileMap to download tiles from a server and overlay that information on the map. In the canDrawMapRect I call a function in the overlay class which in turn creates the url and opens up a connection. I have already tested my connection class and have confirmed that it does indeed work. I've run it in the init functions of overlay and overlayView with success. The urls are good too since I can throw them in a browser and they show the right pngs. I know that canDrawMapRect is running on multiple threads and I only have novice experience with threads.
Here is my connection code,
- (id)initWithStringUrl: (NSString*) url {
NSLog(#"Test Connect Init URL %#", url);
self = [super init];
if (self)
{
[self loadURL:[NSURL URLWithString:url]];
}
return self;
}
+ (UIImage*)connectSynchronousWithURL:(NSString*) url {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSURLResponse* response = [[NSURLResponse alloc] init];
NSError* error = [[NSError alloc] init];
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
UIImage *image = [UIImage imageWithData: data];
return image;
}
- (BOOL)loadURL:(NSURL *)inURL {
NSURLRequest *request = [NSURLRequest requestWithURL:inURL];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
if (conn) {
receivedData = [[NSMutableData data] retain];
NSLog(#"Connection Success");
} else {
NSLog(#"Connection Failed");
return FALSE;
}
return TRUE;
}
- (void)connection:(NSURLConnection *)conn didReceiveResponse:(NSURLResponse *)response {
NSLog(#"didReceiveResponse");
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data {
NSLog(#"didReceiveData");
[receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)conn {
NSLog(#"Succeeded! Received %d bytes of data", [receivedData length]);
}
Pretty standards stuff. If I run the code in the init of TileOverlayView it'll work just fine but if I run it in canDrawMapRect then none of the delegate functions get called. I suppose it's also worth mentioning that the synchronous connection to the server does work in the canDrawMapRect method. I don't get it at all T_T
Any help would be greatly appreciated. Thank you.
From the docs about NSURLConnection, this pretty much sums it up.
Note that these delegate methods will be called on the thread that started the asynchronous load operation for the associated NSURLConnection object.
Looks like I'll be needing to use CFRunLoopRun() and CFRunLoopStop(CFRunLoopGetCurrent()); to keep the thread alive. Or find an alternative to making these async calls in the thread.