NSURLConnection not return data - objective-c

I Have a NSURLConnection that has been working for a while and all of a sudden is not working.
For some reason, the only delegate method that gets called is:
-(void)connection:(NSURLConnection *)connection didReceiveResponse:
None of the other delegate methods get called. I have other classes which uses pretty much the same code, just a different request and url and they all seem to work fine. I have read alot of post that talk about making sure the connection is on the same thread as the delegate etc but nothing seems to work for me. I know the server is returning a response because if I pass the same information through a simple html form I get a response in my browser, and I can see evidence that my server side script is running because I can see the changes it is making in the SQL data. And the app is getting some sort of resonse, its just not getting any data or calling the connectionDidFinishLoading delegate method.
Any ideas of what the problem might be?
Here is a simplified version on my code:
#import "RegistrationViewController.h"
#interface RegistrationViewController ()
#end
NSMutableData *responseData;
NSURLConnection *theconnection;
#implementation RegistrationViewController
/*
* Attempt to Register online. Returns False if valiation failed
*/
- (BOOL) registerOnline{
// OTHER CODE HERE TO BUILD DATA FOR THE REQUEST
// URL Request
NSURL *requestUrl = [NSURL URLWithString:THEURL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:requestUrl];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[NSData dataWithBytes:[bodyData UTF8String] length:strlen([bodyData UTF8String])]];
// Initialse Response Object
responseData = [[NSMutableData alloc] init];
// Conection
theconnection = [NSURLConnection connectionWithRequest:request delegate:self];
[theconnection start];
return YES;
}
/*
* Handle the event of registration failing
*/
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"didFailWithError");
// OTHER CODE HERE TO HANDLE THE ERROR....
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(#"did receive response ");
}
/*
* Handle the reciept of Data
*/
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
NSLog(#"didReceiveData");
// Add data to the response
[responseData appendData:data];\
}
/*
* Data finnished loading
*/
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"connectionDidFinishLoading");
// OTHER CODE HERE TO HANDLE THE RESPONSE....
}

You should look at the response and diagnose what's going on. For example, if statusCode is not 200, you might have a problem. See the HTTP/1.1 Status Code Definitions.
So, you might check the statusCode:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode == 200) {
NSLog(#"received successful (200) response ");
} else {
NSLog(#"whoops, something wrong, received status code of %d", statusCode);
}
} else {
NSLog(#"Not a HTTP response");
}
}
You're also calling:
theconnection = [NSURLConnection connectionWithRequest:request delegate:self];
That starts the connection automatically. By calling
[theconnection start];
you're starting it a second time. Remove the start method, or use initWithRequest:delegate:startImmediately: with NO for that final parameter.

If it can help anybody, the problem for me was that i was starting the connection in an another thread
So be sure to call
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
or
theconnection = [NSURLConnection connectionWithRequest:request delegate:self];
[theconnection start];
in the main thread.

Related

Cannot call method in objective c

I'm having difficulty understanding how to call a method. Here's the code:
- (void)beachJSON
{
// Build the string to call Beach API
NSString *urlString = [NSString stringWithFormat:#"http://nrw-bwq-dev-api.azurewebsites.net/api/Pull"];
// Create NSURL string from formatted string
NSURL *url = [NSURL URLWithString:urlString];
// Setup and start async download
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Store incoming data into a string
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
results = [jsonString JSONValue];
}
- (NSArray *)getBeachList {
[self beachJSON];
return results;
}
I call getBeachList from another class to populate 'results', beachJSON is called fine but I need to call
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
Within
- (NSArray *)getBeachList
i.e. right here
- (NSArray *)getBeachList {
[self beachJSON];
//This is where I want to call it to populate results before it is returned
return results;
}
Calling getBeachList will call beachJSON but the connection method will be skipped over leaving 'results' nil
If i try simply putting
[self connection:(NSURLConnection *)connection didReceiveData:(NSData *)data]
I get a expected expression error on that line.
I'm pretty new to objective c so any help would be great.
You don't need to call this method.
It's a delegate method of NSURLConnection.
What you need is to set a delegate for connection and method will be called by connection when it downloads any data.
You should not call connection:didReceiveData: by yourself. This is an event which is only supposed to be fired by the NSURLConnection instance. As far as I can see the only thing you are missing is the start call, which actually makes the NSURLConnection perform the request.
Try this:
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
Then you should see that your NSURLConnection instance will call your implementation of connection:didReceiveData:.
If you want to be sure that your data is fully loaded you should be using this event instead:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
The connection:didReceiveData: will be called multiple times if your data size is large enough. Every time the NSURLConnection receives data it will invoke connection:didReceiveData:. connectionDidFinishLoading: will only be called once when all your data is ready.

OS X cocoa send HTTP response to PHP page, wait for PHP response to request, Continue

id like to achive what is mentioned in the title, can anyone point me in the right direction regarding ressources or torturials? I do understand the basics of the HTTP protocol, but i am fairly new to OS X programming.
In fact you can use the NSMutableURLRequest, if you want to make a test to start you can do this:
//test.h
#import <Foundation/Foundation.h>
#interface test : NSObject<NSURLConnectionDataDelegate>{
NSMutableData* _responseData;
}
//test.m
#implementation test
//Just call this method to start the request.
-(void)testRequest{
//set request
NSURL url = [NSURL URLWithString:#"http://ip/file.php"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLCacheStorageNotAllowed
timeoutInterval:20.0];
//Start the request
NSURLConnection * connection;
connection = [[NSURLConnection alloc] initWithRequest: request delegate:self];
}
after this you have to implement all the methods as woz said but catching the response:
#pragma mark - NSURLConectionDlegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
_responseData = [[NSMutableData alloc] init];
}
//Receive data from the server
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data to the instance variable
[_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;
}
//in this method you can check the response.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
NSString *receivedDataString = [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
NSLog(#"this is reponse: %#",receivedDataString);
}
server side
//file.php
echo "hello";
I like short solutions, and using blocks.
- (void)sendRequestWithURL:(NSURL*) url {
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
NSLog(#"%#", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
else {
///log error
}
}];
}

ios 4.3 uploading file to wcf json web service

I've been killing myself over this bug/problem for a few days now, and I am going insane. I have no idea why it is break. I was wondering if you guys and gals can lend me a hand and rid of my insanity. So thank you in advance.
What I am trying to do: upload a .wav file to a wcf json web service (.net 4.0) from an iphone app (ios 4.3). I have verified that the service does work from a different client.
The problem: the problem is the same code on the iphone app worked 5 days ago. Yesterday and today the code decided to not work. Nothing had changed on the service side and the iphone app.
I'll post as little code as I can to keep things relevant and simple to the topic. If there is a need to post more code to make it easier for you all, I will.
I am consistently getting status code 400 back from the response in the didReceiveResponse method. I've check the url which i post to many times, and the url seem valid to me.
The size of the file which I am posting to the json web service is 1KB < fileSize < 450KB.
here is a sample url that i post to:
http://random-ec2-id-east-1.elb.amazonaws.com/sampleApp/?key=ee404d54-ea45-421a-9633-1ea35c0c211e&token=zJSRqiZgmU6nOW44CeAzhWYxasdD0158yysNDCiASMk.eyJpdiI6IlU3Y2UwbWNXVGN6WVVBLU42SDVieGcifQ.kLbcRPOJ_QnrrtsBe-zF2-2IIbAffArvqeyAmwp_OpOWAoADMugHYjTPcnjkjQvzxEIMcm2k3933i3GqF2YFhAFDtItwvqre5fIGlixbuwsYhrVCm9FBoue4dCQ_pPX-yjUtq_898FGWa5INl0RG0A&type=c&platform=i
// ################################
- (id)init {
self = [super init];
if (self) {
self.sampleAppInstance = [sampleAppInstance sharedSampleAppInstance];
self.sampleAppUrl = #"http://random-ec2-id.us-east-1.elb.amazonaws.com/sampleApp/";
self.key = #"ee404d54-ea45-421a-9633-1ea35c0c211e";
self.token = self.sampleAppInstance.facebook.accessToken; // facebook access token
self.type = #"c";
self.platform = #"i";
}
return self;
}
// #################################
- (BOOL) save:(NSString *)_fileName {
NSString *url = [NSString stringWithFormat:#"%#?key=%#&token=%#&type=%#&platform=%#", self.sampleAppUrl, self.key, self.token, self.type, self.platform];
NSData *voiceData = [NSData dataWithContentsOfFile:_fileName];
//NSLog(#"%#", url);
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]] autorelease];
[request setValue:#"text/plain" forHTTPHeaderField:#"content-type"];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d", [voiceData length]] forHTTPHeaderField:#"content-length"];
[request setHTTPBody:voiceData];
[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
return FALSE;
}
// #################################
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
//NSLog(#"did failed");
[self.delegate responseDidFailWithError:error];
}
// #################################
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
//NSLog(#"did receive data");
//NSLog(#"%#", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
[self.delegate responseDidReceive:data];
}
// #################################
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
int statusCode = [httpResponse statusCode];
// if get 400, then malform syntax
//NSLog(#"%d", statusCode);
if (statusCode != 200)
[self.delegate responseDidFailWithStatusCode:statusCode];
}
it turns out that my service only accept file size < 65k by default. the fix was to configure my service to accept file > 65k.

NSURLConnection is returning null when XML is expected

I have a basecamp account which I'm trying to access via its XML API.
I have created a NSURL Request with proper header fields.
NSURL* projectsUrl = [NSURL URLWithString:[self.accountURL stringByAppendingString:#"/projects.xml"]];
NSMutableURLRequest* projectsRequest = [NSMutableURLRequest requestWithURL:projectsUrl];
[projectsRequest setValue:#"application/xml" forHTTPHeaderField:#"Content-Type"];
[projectsRequest setValue:#"application/xml" forHTTPHeaderField:#"Accept"];
I create a connection and start it.
NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:projectsRequest delegate:self];
[connection start];
[connection autorelease];
Basecamp uses HTTP basic authentication. So I use a NSCredential object to handle it as below.
-(void) connection:(NSURLConnection*)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge*)authenticationChallenge
{
if ([authenticationChallenge previousFailureCount] <=2 ) {
NSURLCredential* basecampCredentials;
basecampCredentials = [NSURLCredential credentialWithUser:[self username]
password:[self password]
persistence:NSURLCredentialPersistenceNone];
[[authenticationChallenge sender] useCredential:basecampCredentials forAuthenticationChallenge:authenticationChallenge];
}else {
[[authenticationChallenge sender] cancelAuthenticationChallenge:authenticationChallenge];
}
}
And when I receive data from connection i handle it with these delegates.
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[[self responseData] appendData: data];
NSLog(#"I received %#", [self responseData]);
}
-(void) connectionDidFinishLoading:(NSURLConnection*)connection
{
NSLog(#"I FINALLY received %#", [self responseData]);
NSXMLParser* parser = [[NSXMLParser alloc] initWithData:[self responseData]];
[parser setDelegate:self];
BOOL success = [parser parse];
if (success) {
NSLog(#"XML parse success");
}else {
NSLog(#"XML parse ERROR");
}
[parser autorelease];
}
The problem is even after using right urls, authentication credentials and header fields I get null data in responseData whereas when I try to access the same url with curl I get proper xml response from the basecamp server. I'm new to objective C. Please explain and tell me what else should I set to get this right.
Before starting connection ([connection start];) you should initialise property responseData, for example, self.responseData = [[NSMutableData alloc] init];.
In method - (void)connection:(NSURLConnection *)conn didReceiveResponse:(NSURLResponse *)response you should set the length of that data to zero : [self.responseData setLength:0];
Are you sure you set [self responseData]?
Try the same URL with an ASIHTTPRequest and see if it works.

how to do an http post in cocoa on the iPhone

Can anyone paste some code on how to do an http post of a couple values?
Second answer on a google search looks like what you probably need:
http://www.iphonedevforums.com/forum/sample-code/69-getting-content-url.html
// You can drive an NSURLConnection synchronously using sendSynchronousRequest:returningResponse:error:
// but that will block the entire thread until the response is received
// thebodyData = payload sent to server (in the correct format)
// theMimeType = mineType of the payload
//url is the appropriate url for the http POST call
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
[theRequest setHTTPMethod:#"POST"];
NSURLConnection *theConnection = [[NSURLConnection alloc]initWithRequest:theRequest delegate:self];
if(theConnection)
{
webData = [[NSMutableData data]retain];
// give the details of the payload -- mine time and body content.
[theRequest setValue: theMimeType forHTTPHeaderField:#"Content-Type"];
[theRequest setHTTPBody:theBodyData];
}
else
{
NSLog(#"theConnection is NULL");
}
// the delegate methods templates...
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webData setLength:0]; // clear the data incase it was a redirect in between.
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data]; // collect the data from server as it comes in.
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[[NSAlert alertWithError:error] runModal]; // report the error
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Once this method is invoked, "webData" contains the complete result
}
Here is some basic code that doest a POST call:
//url is the appropriate url for the http POST call
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
[theRequest setHTTPMethod:#"POST"];
NSURLConnection *theConnection = [[NSURLConnection alloc]initWithRequest:theRequest delegate:self];
if(theConnection)
{
webData = [[NSMutableData data]retain];
}
else
{
NSLog(#"theConnection is NULL");
}
You need to implement the appropriate delegate methods of the NSURLConnection.