NSURLConnection doesn't receive data - iphone

I have implemented an NSURLConnection that sends a request to a server and receives some data back which is stored in an NSMutableData object. These are the methods that I implemented as part of NSURLConnectionDelegate:
-(void)upLoadBook:(NSMutableDictionary *)theOptions{
NSMutableString *theURL = [[NSMutableString alloc] initWithString:#"theURL"];
[theURL appendFormat:#"&Title=%#&Author=%#&Price=%#", [theOptions objectForKey:#"bookTitle"],
[theOptions objectForKey:#"bookAuthor"],
[theOptions objectForKey:#"bookPrice"]];
[theURL appendFormat:#"&Edition=%#&Condition=%#&Owner=%#", [theOptions objectForKey:#"bookEdition"],
[theOptions objectForKey:#"bookCondition"],
_appDel.userID];
NSLog(#"%#\n", theURL);
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:theURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
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.
receivedData = [NSMutableData data];
}
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[receivedData appendData:data];
}
- (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 an instance variable declared elsewhere.
[receivedData setLength:0];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
// receivedData is declared as a method instance elsewhere
//Receives a response after book has been uploaded (Preferably a Book ID...)
responseString = [[NSString alloc] initWithData:receivedData
encoding:NSUTF8StringEncoding];
NSLog(#"Response String: %#", responseString);
[_options setValue:responseString forKey:#"bookID"];
[self performSegueWithIdentifier:#"UploadSuccessSegue" sender:self];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Whoops." message:#" No internet
connection.\n Please make sure you have a connection to the internet."
delegate:self cancelButtonTitle:#"Ok"
otherButtonTitles: nil];
[alert show];
}
The function uploadBook seems to be called,however, I never get to didFinishLoading and didReceiveData never receives any data. What could be a possible problem. Any hints or clues would be much appreciated.

You need to add your NSURLConnection to the current run loop or a separate one (such as one you set up in a separate thread). The delegate methods do need to get CPU time, after all.
Looking at this related question's accepted answer, it can also be done via Grand Central Dispatch:
dispatch_async(dispatch_get_main_queue(), ^{
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
[conn start];
});

One thing for sure is that you should %-escape your list of parameter before trying to send the request.
You can use stringByAddingPercentEscapesUsingEncoding for that purpose:
NSMutableString *theURL = [[NSMutableString alloc] initWithString:#""];
[theURL appendFormat:#"&Title=%#&Author=%#&Price=%#", [theOptions objectForKey:#"bookTitle"],
[theOptions objectForKey:#"bookAuthor"],
[theOptions objectForKey:#"bookPrice"]];
[theURL appendFormat:#"&Edition=%#&Condition=%#&Owner=%#", [theOptions objectForKey:#"bookEdition"],
[theOptions objectForKey:#"bookCondition"],
_appDel.userID];
theURL = [NSStringWithFormat:#"YOUR_URL_HERE?",[theURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
Please, note that I refactored your code with the minimum number of changes to get the result. You can find better refactorizations for sure.

Here is a sample that works from one of my projects:
NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.brayden.me/analytics/device.php"]];
[urlRequest setHTTPMethod:#"POST"];
NSMutableString *postParams = [NSMutableString string];
[postParams appendFormat:#"session=%#&", analyticsSession];
[postParams appendFormat:#"device=%#&", device];
[postParams appendFormat:#"system=%#&", csystem];
[postParams appendFormat:#"version=%#&", version];
[postParams appendFormat:#"launch=%f&", totalLaunchTime];
if([Analytics_Location location].latitude && [Analytics_Location location].longitude) {
[postParams appendFormat:#"latitude=%#&", [Analytics_Location location].latitude];
[postParams appendFormat:#"longitude=%#&", [Analytics_Location location].longitude];
}
[urlRequest setHTTPBody:[postParams dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self startImmediately:YES];
[connection start];
Make sure your header method also uses . The code of mine should at least show you how to properly format the request, as I can verify this does receive data from a PHP call of mine.

Related

How to make NSURL connection start transmitting data into dictionary item?

I've got the tagged NSURLConnection subclass, and need to fetch Image data from multiple URL-s...The idea is clear to me, but i can't start the connection properly, so that data would append into its place... here i have:
- (IBAction)sophisticatedDownload {
connectionDict = [[NSMutableDictionary dictionaryWithCapacity:news.count] retain];
for (int i =0; i<news.count; i++)
{
//init the tagged connection
if (theConnection) {
self.imageData = [NSMutableData data];
[connectionDict setObject: imageData forKey: theConnection.connID];
} else {
NSLog(#"Connection failed");
}
}
}
- (void)connection :(tagConnection *)connection didReceiveData:(NSData *)data {
[[connectionDict objectForKey:connection.connID] appendData:data];
}
- (void)connectionDidFinishLoading:(tagConnection *)connection {
NSLog(connection.connID);
What should
You can get start you connection like this -
NSString *urlString = [NSString stringWithFormat:#"http://EnterYourURLHere"];
NSURL *URL = [NSURL URLWithString:urlString];
NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc]init];
[urlRequest setURL:URL];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-type"];
NSURLConnection *urlConnection = [[NSURLConnection alloc]initWithRequest:urlRequest delegate:self];
if(!urlConnection)
{
[[[UIAlertView alloc]initWithTitle:#"OOoopppssS !!" message:#"There is an error occured. Please check your internet connection or try again." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil] show];
}
But this is not good approach to download multiple images. See NSURLConnection Download multiple images to download multiple images.

Asynchronous NSURLConnection request responds multiple times

I am facing weired issue. I am sending Asynchronus NSUrlrequest call but in return i am getting multiple time responde with some part of json
can someone please help me with what I did wrong.
code
NSString *_query = #"http://abc.com/index.php";
NSData *myRequestData = [NSData dataWithBytes:[_requestString UTF8String]
length:[_requestString length]];
__block NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:_query]];
[request setHTTPMethod: #"POST" ];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
[request setHTTPBody: myRequestData ];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timeOutTimer forMode:NSDefaultRunLoopMode];
Response
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// check is response is a valid JSON?
NSError *error;
id jsonObj = [NSJSONSerialization JSONObjectWithData: data options:kNilOptions error:&error];
BOOL isValid = [NSJSONSerialization isValidJSONObject:jsonObj];
NSString *content = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(#"Content: %#",content);
if (isValid)
{
NSDictionary *data = [content JSONValue];
}
[content release];
}
As data is received by the client, this callback gets called:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
didReceiveData is giving you data as it's receiving it and can be called multiple times with chunks of the data.
From the NSURLConnection docs:
The delegate is periodically sent connection:didReceiveData: messages
as the data is received. The delegate implementation is responsible
for storing the newly received data.
From those docs:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
}
When its all done, connectionDidFinishLoading will get called and your appended data is ready for you to use.
Finally, if the connection succeeds in downloading the request, the
delegate receives the connectionDidFinishLoading: message. The
delegate will receive no further messages for the connection and the
NSURLConnection object can be released.

How to send Asynchronous URL Request?

I would like to know how do I get a return value 1 or 0 only.... back from an URL request asynchronously.
currently I do it in this way:
NSString *UTCString = [NSString stringWithFormat:#"http://web.blah.net/question/CheckQuestions?utc=%0.f",[lastUTCDate timeIntervalSince1970]];
NSLog(#"UTC String %#",UTCString);
NSURL *updateDataURL = [NSURL URLWithString:UTCString];
NSString *checkValue = [NSString stringWithContentsOfURL:updateDataURL encoding:NSASCIIStringEncoding error:Nil];
NSLog(#"check Value %#",checkValue);
this works, however it is blocking my main thread till I got a reply back from the URL, how do I set it so it will do it in a another thread instead of the main thread ?
EDIT: ANSWER
I end upcalling my function with this, it works well :)
[self performSelectorInBackground:#selector(shouldCheckForUpdate) withObject:nil];
you can use NSURLConnection class
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
and handle its response and errors using its delegate methods.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
You can find implementation of NSURLConnection
Apple docs: Using NSURLConnection
How To Use iOS NSURLConnection By Example
Edit: Although NSURLConnection is provided by apple is more recommended way of placing URL request. But I found AFNetworking library very time saving, easy to implement and robust yet simple as third party implementation. You should give it a try.
try this :
.h:
NSMutableData *responseData;
.m:
- (void)load
{
NSURL *myURL = [NSURL URLWithString:#"http://www.example.com"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[responseData release];
[connection release];
[textView setString:#"Unable to fetch data"];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[responseData
length]);
NSString *txt = [[[NSString alloc] initWithData:responseData encoding: NSASCIIStringEncoding] autorelease];
}
Use NSURLConnection and make your request.
Then you may start synchronous or asynchronous connection with NSURLConnection's methods :
Loading Data Synchronously
+ sendSynchronousRequest:returningResponse:error:
Loading Data Asynchronously
+ connectionWithRequest:delegate:
– initWithRequest:delegate:
– initWithRequest:delegate:startImmediately:
– start
Check the NSURLConnection class in Apple Developer API Reference.
Shamelessly copy from https://gist.github.com/knmshk/3027474. All credits go to https://gist.github.com/knmshk.
xmlData = [[NSMutableData alloc] init];
NSURL *url = [NSURL URLWithString:
#"http://forrums.bignerdranch.com/smartfeed.php?"
#"limit=NO_LIMIT&count_limit20&sort_by=standard&"
#"feed_type=RSS2.0&feed_style=COMPACT"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[NSURLConnection sendAsynchronousRequest:request
queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if (error) {
xmlData = nil;
NSLog(#"error:%#", error.localizedDescription);
}
[xmlData appendData:data];
}];
There is an example in the iOS XCode documentation called LazyTableImages. This does an asynchronous URL as well as asynchronous image load into UITableView cells displayed on the screen after scrolling stops. Excellent example of protocols, asynchronous data handling, etc.

"Operation couldn't be completed. Connection reset by peer." with NSURLConnection on iOS

I'm struggling sending POST data to a server and receiving the correct response. I started by using setHTTPBody but moved to setHTTPBodyStream when I wasn't getting the correct server response for certain POST data and I read setHTTPBody has a memory leak on earlier iOS versions. The problem is setHTTPBodyStream causes the error - "Operation couldn't be completed. Connection reset by peer".
Here's the code:
NSMutableURLRequest * request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"secret but correct url goes here"] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10.0];
[request setHTTPMethod: #"POST"];
[request setHTTPBodyStream: [NSInputStream inputStreamWithData: [[NSString stringWithFormat:#"username=%#&password=%#&score=%i",[(NSString*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)ogl_view->username, NULL, CFSTR("?=&+"), kCFStringEncodingUTF8) autorelease],[(NSString*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)text_field.text, NULL, CFSTR("?=&+"), kCFStringEncodingUTF8) autorelease],ogl_view->score[0]] dataUsingEncoding:NSUnicodeStringEncoding]]];
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest: request delegate:self];
if (connection){
received_data = [[NSMutableData data] retain];
ogl_view->section = CURLING_PROCESS_CREDENTIALS;
}else{
ogl_view->section = CURLING_LOGIN_OR_REGISTER;
UIAlertView *connection_alert = [[UIAlertView alloc] initWithTitle:#"Error" message: #"Can't connect to server" delegate:self cancelButtonTitle:#"Close" otherButtonTitles: nil];
[connection_alert show];
[connection_alert release];
}
I can verify the server is fine and it works when I try a web-browser.
Can somebody get me on the right track to sending data with HTTP and the POST method correctly?
Thank you for any help.
Try using this (with your own values):
NSString* post = #"username=myUser&password=myPass&score=20"; //customize this
NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
NSURL *url = [NSURL URLWithString:#"http://my.request.com"]; //customize this
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
[request setTimeoutInterval:timeout];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
You'll then need to implement the NSURLConnectionDelegate methods:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)remoteData;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
In the end, remember to release the NSURLConnection.
Edit: Didn't see that you wrote that setHTTPBody leaks... never seen that happening. Anyway, here is some code that should work...

connection didReceiveData called twice while posting a Url in iphone?

I am new to iphone development.I have posted the URL with the user-name and password. I am able to print the data in "connection didReceiveData " method.But i see "connection didReceiveData" method called twice.I don't know ,where i am going wrong. Here is my code
- (void)viewDidLoad {
[super viewDidLoad];
NSString *post = [NSString stringWithFormat:#"&domain=school.edu&userType=2&referrer=http://apps.school.edu/navigator/index.jsp&username=%#&password=%#",#"xxxxxxx",#"xxxxxx"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d",[postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://secure.school.edu/login/process.do"]]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Current-Type"];
[request setHTTPBody:postData];
NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if(conn)
{
NSLog(#"Connection Successful");
}
else
{
NSLog(#"Connection could not be made");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data{
NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"the data %#",string);
}
The whole HTML page is printed twice in the console.So please help me out.Thanks.
You may receive the response data in chunks, which is why NSURLConnection's documentation states:
"The delegate should concatenate the contents of each data object delivered to build up the complete data for a URL load."
Use an instance of NSMutableData for this and only process the complete data once you receive the -connectionDidFinishLoading: message.
As MacOS Developer Library states, connection:didReceiveData can be called multiple times if data is received in chunks. That means you have to save all the chunks in some variable and do data processing in connectionDidFinishLoading method. e.g.
NSMutableData *receivedData = [[NSMutableData alloc] init];
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
[receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data, for example log:
NSLog(#"data: %#", [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding]
}