What's the equivlent code for stringWithContentsOfURL using a NSURLRequest? - objective-c

NSURL *url = [NSURL URLWithString:escapedUrlString];
NSString *responseString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
But, I was reading online that I should probably be using an NSURLRequest instead if I want to add a timeout. The first code works fine, but the second code always returns #"" (not nil, just ""). Anyone have any suggestions?
I also read that the NSURLConnection takes care of any sort of web compression that might be done whereas NSURLRequest won't handle that, so I thought I better just go for the more well rounded solution.
http://lists.apple.com/archives/cocoa-dev/2009/Oct/msg01921.html
NSString *escapedUrlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *responseString;
NSURLResponse *response;
NSError *error;
NSURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:[NSURL URLWithString:escapedUrlString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:5]; // 5 second timeout?
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]){
NSLog(#"Recieved String Result: %#", responseString);
} else {
NSLog(#"Response String is null!");
}

Thanks for the good suggestions. The code magically worked this morning, so I'm guessing my webserver went down or something last night.

Related

App crashes on slow InternetConnection

I am getting data from server in applicationDidBecomeActive method.When net connection is too slow app keep crashing.I do not know how to handle this problem.any help will be appreciated.thanks in advance.
NSString *post =[[NSString alloc] initWithFormat:#"=%##=%#",myString,acMobileno];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http:///?data=%#&no=%#",myString,acMobileno]];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
NSError *error1 = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error1];
NSString *string;
if ([response statusCode] >=200 && [response statusCode] <300)
{
string = [[NSString alloc] initWithData:urlData encoding:NSMacOSRomanStringEncoding];
}
It's probably crashing because the connection has started downloading, but it hasn't finished therefore allowing the complier to pass your if statement, which would inevitably give a nil urlData parameter.
To fix this, you should be checking to see if there is an error, and then the response headers for the download. Also, I recommend running this operation on a background thread so that it doesn't block the user experience - at the moment, the app will have a delayed launch depending on the size of your file, and the user's download speed.
NSError *error1 = nil;
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error1];
NSString *string = nil;
if (error != nil && ([response statusCode] >=200 && [response statusCode] <300)){
string = [[NSString alloc] initWithData:urlData encoding:NSMacOSRomanStringEncoding];
}
else {
NSLog(#"received error: %#", error.localizedDescription);
}
For a background thread, run the above code in a dispatch_async statement, or use -sendAsynchronousRequest: instead of -sendSynchronousRequest.
Alternatively, as #Viral said, it is possible that the request is taking too long, and the app is hanging as a result of the synchronous request not finishing before the UI should have been loaded.
Most probably, it's due to synchronous call in Application's delegate method. It is taking too much time to load the UI (As internet connection is slow and you are calling the web service on main thread); and therefore OS thinks your App has hanged due to unresponsive UI and crash the App itself.
Just for debugging purpose, try the same code in your FirstViewController's viewDidAppear method. It should work fine there. And if it is so, you need to change your call to somewhere else (also, preferably in some background thread, OR Async).
EDIT: Though, If it works elsewhere, you need to change the call as Async OR on background thread for smoother UX.

Obj-C NSURLConnection not working

So i am trying to send data to a webservice via url with a parameter. the code i have is below but it never hits the server. the request and responses are null. What am i doing wrong?
-(void) postData:(NSString *)data{
NSURLResponse* response;
NSError* error = nil;
NSString *urlString = [NSString stringWithFormat:#"http://someaddress.com/api?data=%#", data];
NSURL *lookupURL = [NSURL URLWithString:urlString];
//Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:lookupURL];
NSData *request = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&response error:&error];
NSString *dataString = [[NSString alloc] initWithData:request encoding:NSUTF8StringEncoding];
NSLog(#"-----------------------------");
NSLog(#"Request: %#", theRequest);
NSLog(#"req response: %#", request);
NSLog(#"response: %#", dataString);}
you want to POST some binary data but you do a GET request and try to put the binary into the url. (without encoding it)
sample post:
NSURL *url = [NSURL URLWithString:#"http://server.com"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = #"POST";
request.HTTPBody = postData;
NSData *respData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
also, note that the synchronous get is bad as it blocks :) use async networking!

NSURLConnection closes early on GET

I'm working on a method to centralize my URL connections for sending and receiving JSON data from a server. It works with POST, but not GET. I'm using a Google App Engine server and on my computer it'll handle the POST requests and return proper results (and log appropriately), but I get the following error when I try the request with a GET method:
Error Domain=kCFErrorDomainCFNetwork Code=303 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 303.)" UserInfo=0xd57e400 {NSErrorFailingURLKey=http://localhost:8080/api/login, NSErrorFailingURLStringKey=http://localhost:8080/api/login}
In addition, the GAE dev server shows a "broken pipe" error, indicating that the client closed the connection before the server was finished sending all data.
Here's the method:
/* Connects to a given URL and sends JSON data via HTTP request and returns the result of the request as a dict */
- (id) sendRequestToModule:(NSString*) module ofType:(NSString*) type function:(NSString*) func params:(NSDictionary*) params {
NSString *str_params = [NSDictionary dictionaryWithObjectsAndKeys:func, #"function", params, #"params", nil];
NSString *str_url = [NSString stringWithFormat:#"%#%#", lds_url, module];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:str_url]];
NSData *data = [[NSString stringWithFormat:#"action=%#", [str_params JSONString]] dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:type];
[request setHTTPBody:data];
[request setValue:[NSString stringWithFormat:#"%d", [data length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSError *error = nil;
NSURLResponse *response = nil;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Error: %#", error);
NSLog(#"Result: %#", [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]);
return [result objectFromJSONData];
}
A sample call would be:
NSDictionary *response = [fetcher sendRequestToModule:#"login" ofType:#"GET" function:#"validate_email" params:dict];
Again, this works with a POST but not a GET. How can I fix this?
In my case i was not calling [request setHTTPMethod: #"POST" ]
I think the root cause is you have an invalid URL.
JSON encoding will include things like '{', '}', '[' and ']'. All of these need to be URL encoded before being added to a URL.
NSString *query = [NSString stringWithFormat:#"?action=%#", [str_params JSONString]];
query = [query stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#", str_url, query]];
To directly answer your question:
According to CFNetwork Error Codes Reference the error is kCFErrorHTTPParseFailure. This means the client failed to correctly parse the HTTP response.
The reason why is that a GET doesn't include a body. Why would you want to submit JSON in a GET anyways?
If the target api returns data only you pass it in the url params.
If you want to send data and "get" a response use a post and examine the body on return.
Sample Post:
NSError *error;
NSString *urlString = [[NSString alloc] initWithFormat:#"http://%#:%#/XXXX/MVC Controller Method/%#",self.ServerName, self.Port, sessionId ];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding ]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
// hydrate the remote object
NSString *returnString = [rdc JSONRepresentation];
NSData *s10 = [returnString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:s10];
NSURLResponse *theResponse = [[NSURLResponse alloc] init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&error];
NSString *message = [[NSString alloc] initWithFormat: #"nothing"];
if (error) {
message = [[NSString alloc] initWithFormat:#"Error: %#", error];
} else {
message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
NSLog(#"%#", message);
return message;

Uploading Photo with ASIHTTPRequest

I'm using ASIHTTPRequest to upload a photo with PHP. The PHP side is proven to work(I'm using it for android), and I'm trying to get the iOS component to work.
Here is my upload:
NSString *myurl = #"http://mydomain.tld/php/upload.php?casenum=";
myurl = [myurl stringByAppendingFormat: casenumber];
NSString *fixedURL = [myurl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSString stringWithFormat:#"%#",fixedURL];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
NSData *imageData = UIImageJPEGRepresentation(image1.image, 90);
[request setData:imageData withFileName:#"myphoto.jpg" andContentType:#"image/jpeg" forKey:#"file"];
[request setCompletionBlock:^{
NSString *responseString = [request responseString];
NSLog(#"Response: %#", responseString);
}];
[request setFailedBlock:^{
NSError *error = [request error];
NSLog(#"Error: %#", error.localizedDescription);
}];
[request startAsynchronous];
Ive found this on the internet and when I run it, it fails with the error 2012-01-17 10:52:16.939 MyApp[30373:707] Error: NSInvalidArgumentException
From many of the documentation and examples I've found online, this should work, but it isn't, as you can see with the exception. Any help at ironing out the kinks? If you need any other information, I'll gladly post it.
There would appear to be a couple of errors in the way that you're producing the NSURL. Firstly, it's only the parameters that need escaping, not the whole URL, so
NSString *myurl = #"http://mydomain.tld/php/upload.php?casenum=";
myurl = [myurl stringByAppendingFormat: casenumber];
NSString *fixedURL = [myurl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
should be
NSString *myurl = #"http://mydomain.tld/php/upload.php?casenum=";
NSString *escapedCasenumber = [casenumber stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
myurl = [myurl stringByAppendingFormat:escapedCasenumber];
Secondly, you're then trying to assign an NSString to an NSURL, so
NSURL *url = [NSString stringWithFormat:#"%#",fixedURL];
should be
NSURL *url = [NSURL urlWithString:myurl];
Finally, the second argument passed to UIImageJPEGRepresentation should be a float value between 0.0 and 1.0, so I'm guessing
NSData *imageData = UIImageJPEGRepresentation(image1.image, 90);
should be
NSData *imageData = UIImageJPEGRepresentation(image1.image, 0.9);
If it still doesn't work after these changes, then do as JosephH suggests and use the debugger to identify exactly which line is causing the exception

get data from url xcode

i am trying to load the data from an online link that works with php. The link returns an xml.
That xml i want to save in the Documents Directory from the iPad.
I am trying this:
NSString *post = #"";
NSData *postData = [post dataUsingEncoding:NSISOLatin1StringEncoding allowLossyConversion:NO];
NSMutableURLRequest *urlRequest = [[[NSMutableURLRequest alloc] init] autorelease];
[urlRequest setURL:[NSURL URLWithString:#"http://www.test.be/tools/xml_nieuwsbrief.php"]];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:postData];
NSData *urlData;
NSURLResponse *response;
NSError *error;
urlData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
if(!urlData) {
NSLog(#"No connection!");
}
NSLog(#"Receive:%d bytes",[urlData length]);
NSString *aStr = [[[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding]autorelease];
NSLog(#"________%#", aStr);
the string does return - null -, i a have been searching the internet, but does not find anything that can lead me to my problem.
Can someone help me for letting me see what i am doing wrong?
Thanks in advance,
Snowy
I'd check the status code of the response object (change the NSURLResponse object into an NSHTTPURLResponse and you'll have a statusCode property available).
If you are actually getting - null - out of the NSData-response you should probably be looking at the server-side script. Perhaps it is not expecting an empty POST-request?