I have a chat like app, and to receive periodic chats, I want to poll server at regular intervals , say 5 mins..and check if there are any new messages.
As a beginner, I have tried simple NSURLConnection and send and receive data, but stuck while polling.
What is a correct way of polling? Should I use NSTimer to poll regularly?
Is there any sample code that can help me?
I have a timer running on main thread which invokes a background thread every 5 seconds and sends request to server. Now what happening is, the delegates for NSURLConnection are not getting called. What can be done?
Please help.
Thanks
You can launch an NSTimer on a background thread and make calls to the main thread periodically, this is how I do it:
[self performSelectorOnMainThread:#selector(LaunchTimer) withObject:nil waitUntilDone:NO];
Just make a "LaunchTimer" function that calls an update function at a certain interval, which makes a call to NSURLConnection, and when you receive the new messages, update the chat window by making a call to the main thread like so:
[self performSelectorOnMainThread:#selector(update:) withObject:newMessages waitUntilDone:NO];
Continuing from answer of Patrick :- If you can try NSURLConnection without delegate,
-(void)update:(id)objmessage
{
NSString *post =[NSString stringWithFormat:#"timestamp=%#&user_id=%#",DatetimeString,UID];
NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:#"Your server URL"]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSError *error;
NSURLResponse *response;
NSData *returnData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
returnString=[[NSString alloc]initWithData:returnData encoding:NSUTF8StringEncoding];
if(!returnString)
{
UIAlertView *erroralert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"There is an error getting response" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[erroralert show];
[erroralert release];
}
else
{
NSLog(#"%#",returnString);
}
SBJSON *json = [[SBJSON new] autorelease];
NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithDictionary:[json objectWithString:returnString error:nil]];
//NSLog(#"%#",dic);
}
Solved this with following method:
[self performSelectorOnMainThread:#selector(performPollinginBackground) withObject:nil waitUntilDone:NO];
-(void)performPollinginBackground{
//call server task here
}
Related
I am trying to detect if there is an error in my request using the if statement on theConnection. It enters the first part if successful fine but does not enter the else if there is an error. I am not sure why.
- (void)vehicleSearchRequest:(NSData *)postBodyData
{
NSString *address = [NSString stringWithFormat:#"http://%#", serverAddress];
//Set database address
NSMutableString *databaseURL = [[NSMutableString alloc] initWithFormat:#"%#", address];
NSURL *url = [NSURL URLWithString:databaseURL];
NSString *postLength = [NSString stringWithFormat:#"%d", [postBodyData length]];
//SynchronousRequest to grab the data, also setting up the cachePolicy
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; //if request dose not finish happen within 60 second timeout.
// Set up request
[request setHTTPMethod: #"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/octet-stream" forHTTPHeaderField:#"content-type"];
[request setHTTPBody:postBodyData];
[request setTimeoutInterval:180];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if (theConnection) {
// do animation thankyou here
NSLog(#"Sucsess!");
[self submitSuccessful];
} else {
// Inform the user that the connection failed from the connection:didFailWithError method
NSLog(#"Connectin ERROR!!!");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Connection error, Please try again" message:nil delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
Your code checks to see whether it was able to instantiate an NSURLConnection or not. This is a useful safety check, but will only fail in practice if you pass it a URL that the system does not support.
The connection itself is asynchronous, and so will take a little while to tell you if there was a problem or not. Implement its delegate methods to hear back from the server.
When I chnage to port number I'm connecting to to test the timout, my app freezes.
I am calling [request setTimeoutInterval:10];, which I assume should be 10 seconds. But, the app hangs. Could it have something to do with it being a local server?
Code:
// call this when program first starts
-(void) nSendMessage : (NSString *) name Password: (NSString *) password page: (NSString *) page
{
// set the url
NSString *address = #"http://localhost:1075/update";
address=[ address stringByAppendingString: page];
NSMutableURLRequest *request =
[[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString:address]];
// post or get
[request setHTTPMethod:#"POST"];
// data to send
NSString *postString = #"username=iusername&password=ipassword";
NSString *sendString=[postString stringByReplacingOccurrencesOfString:#"iusername" withString: name];
sendString=[sendString stringByReplacingOccurrencesOfString:#"ipassword" withString: password];
[request setValue:[NSString
stringWithFormat:#"%d", [sendString length]]
forHTTPHeaderField:#"Content-length"];
[request setHTTPBody:[sendString
dataUsingEncoding:NSUTF8StringEncoding]];
[request setTimeoutInterval:10];
[[NSURLConnection alloc]
initWithRequest:request delegate:self];
//
//THE PROGRAM FREEZES HERE
//
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *response = [[NSString alloc] initWithData:urlData encoding:NSASCIIStringEncoding];
// Phrase repl
[self nUpdateDisplay:response];
}
Your question looks like a dupe of this one:
iPhone SDK: URL request not timing out
So to summarise: the timeout lower limit is at least four minutes, even if you pass in a smaller value.
And as detailed at the above link, using the asynchronous method is usually the best option. If you use synchronous, as you are doing above, and you're in the main runloop, you will block your UI completely, which will cause the 'hang' effect.
I want to make login application. My first screen login form with two text fields and one button. When I pres this button I invoke one method that invoke this method:
- (int)login {
// Add data to post request
NSHTTPURLResponse * response;
NSString *myRequestString = [[NSString alloc] initWithFormat:#"userdata='%#'&passdata='%#'",
username.text, password.text];
NSError * error;
NSData *myRequestData = [NSData dataWithBytes: [myRequestString UTF8String] length: [myRequestString length]];
NSMutableURLRequest *request;
request = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://server.com/login.php"]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60] autorelease];
[request setHTTPMethod: #"POST"];
[request setHTTPBody: myRequestData];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
NSData * data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSArray * all = [NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:[NSURL URLWithString:#"http://server.com/login.php"]];
//int cid;
for (NSHTTPCookie *cookie in all) {
NSLog(#"Name: %# : Value: %#", cookie.name, cookie.value);
// cid = (int)cookie.value;
}
// NSLog(#"id: %d",cid);
[myRequestString release];
[request release];
return 1;
}
When I pres this button my program crash and next to this row:
NSArray * all = [NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:[NSURL URLWithString:#"http://sms.britecs.com/login.php"]];
i have Thread1: Program received signal: "EXC_BAD_ACCESS" but don't know how to fix it.
I have one more question. How can I use this cookies in my next screen?
Thanks
With [request release]; you are releasing an autoreleased object. Don't do that, it'll be released the next run loop cycle by the autorelease pool. Remove the autorelease at the end of the initialization and you are fine, else remove the release statement.
Here you are creating it:
request = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://server.com/login.php"]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60] autorelease]; // <---
I have an API call. It takes more than 2 minute to get a response from the server. how can i abort it manually while it is processing?
Here is my code:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setTimeoutInterval: 600.0];
[request setHTTPMethod:#"GET"];
NSMutableDictionary* headers = [[[NSMutableDictionary alloc] init] autorelease];
[headers setValue:#"application/json" forKey:#"Content-Type"];
[headers setValue:#"application/json" forKey:#"Accept"];
[headers setValue:val forKey:#"Authorization"];
[request setAllHTTPHeaderFields:headers];
NSError *Error;
NSURLResponse *response = [[NSURLResponse alloc] init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&Error];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
how can i abort the request while its processing.
Thanks
You can't. Use asynchronous connections if you want to be able to cancel.
Also, BTW, you have some errors in your code:
NSError *Error;
NSURLResponse *response = [[NSURLResponse alloc] init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&Error];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
For good measure, Error should be initialized to nil.
You are leaking response. Initialize it to nil, and sendSynchronousRequest:returningResponse:error: will fill it in (if the request succeeds, anyway).
The line [[NSURLConnection alloc] initWithRequest:request delegate:self] starts an asynchronous connection and releases it, after you already did a synchronous connection for the same request. And it leaks the NSURLConnection object. Did you even implement the necessary methods for the informal delegate protocol on your self object?
You can't, as the thread is being blocked by your synchronous request.
synchronous load is built on top of the asynchronous loading code made available by the class. The calling thread is blocked while the asynchronous (sic) loading system performs the URL load on a thread spawned specifically for this load request.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html
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...