Asynchronous NSURLConnection request responds multiple times - iphone

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.

Related

Iphone-SBJson returns null responseData for the connection which get late response in multiple request sending

Here, I tried to send Asynchronous call to python server using SBJson framework. For continuous multiple call with same request, gives null value in response string.
here, what I tried :
- (NSURLConnection *) GetHttpConnection:(NSString *)Path:(NSDictionary *)requestData:(UIView *)appView {
NSString *jsonReq = nil;
NSData *reqData = nil;
if (requestData != nil) {
jsonReq = [requestData JSONRepresentation];
reqData=[NSData dataWithBytes:[jsonReq UTF8String] length:[jsonReq length]];
}
NSString *urlString = [NSString stringWithFormat:#"%#/%#", URL, Path];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
if (reqData) {
[request setHTTPBody:reqData];
}
[request setHTTPMethod:#"POST"];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if (connection) {
responseData = [[NSMutableData data] retain];
}
return connection;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"Connection Finish Loading >>>>> %#",responseString);
responseData = nil;
if (responseString && [responseString JSONValue] != nil) {
// process response string and send response back to delegate method
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSMutableData*)data {
[responseData appendData:data];
}
After tracing NSlog responses, I found this,
If I send same request 3 times (by pressing Update detail button)
connectionDidFinishLoading should call 3 times and it is calling it. but for any (one) request the respective response data returns null. Thats why the JSON stated below
JSONValue failed. Error trace is: (
"Error Domain=org.brautaset.JSON.ErrorDomain Code=11 \"Unexpected end of string\" UserInfo=0x909d4b0 {NSLocalizedDescription=Unexpected
end of string}"
How can I overcome from this scenario? or Is there anything wrong in the code?
Thanks!
Your class is not re-entrant as there's only one reference to responseData. If two requests run at the same time Bad Things Will Happen. For this to work you'll need to either put your requestData in a dictionary keyed by the NSURLConnection, or create another instance of your downloader for each request.

iPhone authentication process

I have trouble finding info on this topic. Please help me out here.
I need to pass arguments via POST or GET method to my web server and get a reply.
Basically, if using GET method, I want to do something like server.com/?user=john&password=smith and receive the dynamically generated HTML code that is done with my php script. All this without using the web browser on my app.
How is it usually done?
You'll want to look into NSMutableURLRequest and NSURLConnection.
For example, you could use them like this do to a GET request to your server:
- (void)loginUser:(NSString *)username withPassword:(NSString *)password {
// GET
NSString *serverURL = [NSString stringWithFormat:#"http://yourserver.com/login.php?user=%#&pass=%#", username, password];
NSURL *url = [NSURL URLWithString:serverURL];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:req delegate:self];
if (connection) {
connectionData = [[NSMutableData alloc] init];
}
}
This will send an asynchronous GET request to your server with the query string containing username and password.
If you want to send username and password using a POST request, the method would look something like this:
- (void)loginUser:(NSString *)username withPassword:(NSString *)password {
// POST
NSString *myRequestString = [NSString stringWithFormat:#"user=%#&pass=%#",username,password];
NSData *myRequestData = [NSData dataWithBytes: [myRequestString UTF8String] length: [myRequestString length]];
NSURL *url = [NSURL URLWithString:#"http://yourserver.com/login.php"];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
[req setHTTPMethod: #"POST"];
[req setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
[req setHTTPBody: myRequestData];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:req delegate:self];
if (connection) {
connectionData = [[NSMutableData alloc] init];
}
}
In order to get the response from the server, you will need to implement the NSURLConnection delegate methods, for example:
#pragma mark -
#pragma mark NSURLConnection delegate methods
#pragma mark -
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
// Called if you have an .htaccess auth. on server
NSURLCredential *newCredential;
newCredential = [NSURLCredential credentialWithUser:#"your_username" password:#"your_password" persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
}
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[connectionData setLength: 0];
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[connectionData appendData:data];
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[connectionData release];
}
-(void) connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *content = [[NSString alloc] initWithBytes:[connectionData bytes]
length:[connectionData length] encoding: NSUTF8StringEncoding];
// This will be your server's HTML response
NSLog(#"response: %#",content);
[content release];
[connectionData release];
}
References:
NSMutableURLRequest Class Reference
NSURLConnection Class Reference
Hope this helps :)
Usually this is done using a NSURLConnection. You can also use NSString's method stringWithContentsOfURL.

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.

How to get data back from webserver with NSMutableURLRequest

I try to build an app for user that enter his data and this data will be post to a webserver for save in a Database. This web server returns some data back like Id or something else.
How I can receive the data the webserver returns back?
The transfer works already with NSMutableURLRequest. But I search for a sollution to read the answer from the web server and display it on a label.
Have a look at the delegate methods of NSURLConnection.
Example of how it could be done. Original source
NSString *post = #"key1=val1&key2=val2";
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:#"http://www.someurl.com"]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *conn=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if (conn)
{
receivedData = [[NSMutableData data] retain];
}
else
{
// inform the user that the download could not be made
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
// receivedData is declared as a method instance elsewhere
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
NSString *aStr = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
NSLog(aStr);
// release the connection, and the data object
[receivedData release];
}

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]
}