how to wait the response from a http request in ios - ios

Anybody knows how to wait the response of a http request? In my code, I am doing a http request to an url and then what i need to do, it is to check the http response in order to decide different treatment. I have something like this:
-(void)check{
[self fetchURL:#"http://something"];
if(response != nil || [response length] != 0){
do something....
}
else{
do something else....
}
}
-(void)fetchURL:(NSString *)urlWeb{
NSURL *url = [NSURL URLWithString:urlWeb];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(#"INSIDE OF didReceiveResponse");
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"INSIDE OF didFailWithError");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"INSIDE OF connectionDidFinishLoading");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
NSLog(#"inside of didReceiveData");
response = [NSString stringWithUTF8String:[data bytes]];
NSLog(#"response: %#", response);
}
I have been trying different options that I have seen around here, but i cant stop the execution of my code and wait for that answer...that means when I check the response of my http request, it always appears empty or with a nil reference...
any help how to figure out??
thanks

You can't evaluate the response value right after your 'fetchUrl' call, because your request is asynchronous, and your code goes on with the execution without waiting for the answer. You will receive the response value only in one of the delegate method, so there's the place where you should check the result.
If you really want to make a synchronous request you can use sendSynchronousRequest:returningResponse:error: like this
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(data){
//use data
}
else{
//check error domain and code
}
(See the Apple NSURLConnection Reference)
But keep in mind that your program will be stuck on this call till it receives a response or goes timeout.

Why don't you write this code:
if(response != nil || [response length] != 0){
do something....
}
else{
do something else....
}
In - (void)connectionDidFinishLoading:(NSURLConnection *)connection; method it wouldn't execute unless you have your complete proper response.
And Just for ado: Right to way to get data properly should be:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[_responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSString *string = [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
if (string)
NSLog(#"string = %#", string);
}

Did you try checking the respons witin connectionDidFinishLoading: ?
That is the very delegate method which is called when the data was transferred successfully. Before that point in time, you should not expect any meaningful data.
Besides - didReceiveData should provide you with portions of data received in the meantime. Apparently you do not seem to process it nor just to store it for later evaluation (witin connectionDidFinishLoading)

Related

how to send http request from non ui thread in ios

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
}

iOS NSURLRequests Status Code Always 200

Our requirements include checking Internet access to a specific file on the web-server. This file is checked every n minutes. NSURLRequests never calls connection:didFailWithError whether or not there is an internet connection. And the HTTP status is always 200. Apple's reachibility only works for domains, not files- so it doesn't meet the requirements. How can I reliably discover if I can reach this file every n minutes? Why isn't the http status code really the http status code?
Other stackoverflow questions that would seem to answer this question do not work:
1. How could connectionDidFinishLoading: run if no file is found on server?
2. Testing use of NSURLConnection with HTTP response error statuses
I tried using another queue with a completion block, but that also didn't work.
-(void) updateConnectionStatus
{
NSURL *url = [NSURL URLWithString:(NSString*)[appValues getValueForSettingsKey:#"company.project.test.pingURL"]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
//NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//__block __typeof__(self) _self = self;
connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
/*
[NSURLConnection
sendAsynchronousRequest:urlRequest queue:queue
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
int code = [httpResponse statusCode]; // ALWAYS 200 no matter what
NSString *pingFile = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#",error); // NEVER has an error
//This doesn't even work because it remembers FOREVER the value once it gets it.
if ([#"Ping!" isEqualToString:pingFile])
{
dispatch_async(dispatch_get_main_queue(), ^{
[_self companyConnection:YES];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[_self companyConnection:NO];
});
}
}];
*/
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"ERROR: %#", error); // Never get here
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse *aResponse = (NSHTTPURLResponse*)response;
NSLog(#"received a response: %ld",(long)[aResponse statusCode] );
if ([response respondsToSelector:#selector(statusCode)])
{
int statusCode = [((NSHTTPURLResponse *)response) statusCode];
// statusCode is always 200
if (statusCode >= 400)
{
[companyConnection cancel]; // stop connecting; no more delegate messages
NSDictionary *errorInfo
= [NSDictionary dictionaryWithObject:[NSString stringWithFormat:
NSLocalizedString(#"Server returned status code %d",#""),
statusCode]
forKey:NSLocalizedDescriptionKey];
}
}
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"received data");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Finished");
}
Try with setting cachePolicy as NSURLRequestReloadIgnoringCacheData while constructing the NSURLRequest object
Thanks to Wain and Rob for putting me onto the right path. One way to keep the cache clear is adding this method to your NSURLConnectionDelegate:
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}

Not able to download a file with NSURLRequest

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.

Initializing NSString 's length limit

In the code below, I am looking for a way to limit the length of connected string. Let's say I only want to retrieve the first 100 characters. But I do not want to do the processing connected after retrieving. Is there a way to initialize NSString with certain length?
NSError* error = nil;
NSString *connected = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://www.somesite.com"] encoding:NSASCIIStringEncoding error:&error];
You're going to have to retrieve the data yourself instead of using NSString's convenience method to do it. If you use, say, NSURLConnection or ASIHTTPRequest you can close the connection when you've received as much data as you want.
You could use NSString methods to retrieve the first 100 characters but you would have wasted bandwidth anyway to get all the data. So why download all when you want only 100 chars.
So to get only a slice of the data coming off the server, you need count the data stream that the url response gives. For this you could use NSURLConnection -
- (void)viewDidLoad {
[super viewDidLoad];
responseData = [[NSMutableData data] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://someurl.com/data.json"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if([responseData length] <= 100)
[responseData appendData:data];
else //break connection
[self connectionDidFinishLoading:connection];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
label.text = [NSString stringWithFormat:#"Connection failed: %#", [error description]];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
}
So you need to put your logic in didReceiveData. For here, you want only 100 chars, so break-off the connection after that number is reached.

Upload and download data from server with Cocoa Touch?

How can I upload/download data from a server in Cocoa Touch. Here's what I have so far...
-(void)uploadSchedule:(id)sender
{
NSData *content = [NSData dataWithContentsOfFile:self.dataFilePath];
NSString *stuff = [[NSString alloc] initWithData:content encoding:NSASCIIStringEncoding];
NSURL *url = [NSURL URLWithString:#"http://thetis.lunarmania.com"];
NSMutableURLRequest* urlRequest = [[NSMutableURLRequest alloc]initWithURL:url];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[stuff dataUsingEncoding:NSASCIIStringEncoding]];
NSLog(#"great success!");
}
-(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
// it can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is declared as a method instance elsewhere
[receivedData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// append the new data to the receivedData
// receivedData is declared as a method instance elsewhere
[receivedData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
UIImage *image = [[UIImage alloc] initWithData:receivedData];
[cat setImage:image];
[image release];
// receivedData is declared as a method instance elsewhere
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
// release the connection, and the data object
[connection release];
[receivedData release];
}
-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge previousFailureCount] == 0) {
NSURLCredential *newCredential;
newCredential=[NSURLCredential credentialWithUser:#"ican#moeyo.org"
password:#"icanican"
persistence:NSURLCredentialPersistenceNone];
[[challenge sender] useCredential:newCredential
forAuthenticationChallenge:challenge];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
// inform the user that the user name and password
// in the preferences are incorrect
//[self showPreferencesCredentialsAreIncorrectPanel:self];
}
}
I'm so lost...
The code crashes because you over-release connection. Review the Cocoa memory management rules.
Aside from that, you'll have to be more specific about what problem you're having with it.
BTW, the term is “instance variable”, not “method instance”. An instance variable is a variable inside of an instance, and has nothing to do with methods.
This has been covered here:
NSURLRequest - encode url for NSURLRequest POST Body (iPhone objective-C)
The accepted answer uses ASIHTTPRequest which is similar to one I've used, and makes it really easy to post/get from an HTML form. Here's an example (from past stackoverflow)
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:#"http://someSite.com"] autorelease];
[request setPostValue:#"myValue1" forKey:#"myFormField1"];
[request setPostValue:#"myValue2" forKey:#"myFormField2"];
// etc.
[request start];
NSError *error = [request error];
if (!error)
NSString *response = [request responseString];
And if your file is big, you should better use NSFilehandle, to write data inside didReceiveData, instead of appending.

Resources