iPhone Web service Request Timeout - iphone

I am having problems in my iphone application due to weak wifi signals. My application uses webservice to retireve data from our server but when Wifi signals are weak the response never comes back and user gets stuck on "Loading..." overlay screen. Finally the application crashes at the end. How can i handle this situation gracefully. Is there a way to set TimeOut for my webservice calls or something like this?
Thanks, Asif.

try to use ASIHTTP lib
http://allseeing-i.com/ASIHTTPRequest/How-to-use

You might want to learn about ASIHTTPRequest as it features much more than the standard CFNetwork api. The code is straight forward, error handling as well:
- (IBAction)grabURLInBackground:(id)sender
{
NSURL *url = [NSURL URLWithString:#"http://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
// Use when fetching binary data
NSData *responseData = [request responseData];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
}

You can set the NSURLConnection timeout and a delegate to respond to connection:didFailWithError: selector. See this S.O. topic.
if your delegate is never being called, this is a somehow known issue.
The only workaround seems to be setting your own NSTimer to fire after some time and cancel the request. It is definitely awkard, but it should not be that complex.
If you are curious about the reason behind the issue with timeout, it seems to be related to the slow starting of the 3G subsystem in an iPhone.

Related

How to continuously get Http response without crashing?

I am calling API continuously with 5 seconds interval using the following code:
NSURL *url=[NSURL URLWithString:#"any url"];
ASIFormDataRequest *request=[[ASIFormDataRequest alloc] initWithURL:url];
[request setRequestMethod:#"POST"];
[request setDelegate:self];
[request addRequestHeader:#"Accept" value:#"application/json"];
[request addPostValue:app.userName forKey:#"username"];
[request addPostValue:app.token forKey:#"token"];
[request setTimeOutSeconds:40];
[request startSynchronous];
NSError *error = [request error];
if (!error)
{ //sucesss
} "
The problem I have is after approximately 15-20 minutes, the app crashes with bad access error. I have enabled zombie objects but I didn't get any message on console. Am I doing anything wrong, or can you tell me a standard way to call an api continuously? Thanks.
Have you checked the app's memory usage? Is it possible that the way you are calling this every 5 seconds means that the objects you are alloc-initing aren't getting released, so you're just running out of memory? I'm assuming you're using NSTimer?
(On a second note, why are you using a delegate for a synchronous call? You can sometimes get odd errors if you don't unset them before they are released.)
In terms of standard ways to do this, the only thing I'd recommend is that you do this on a background thread then using notifications to update the UI.
Also, check your calling code as if you call this every 5 seconds, but with a 40 second timeout you could be stacking things up a bit (unless you stop the timer at the start, then reset it to 5 seconds at the end of this code).

ASIHTTPRequest in ASINetworkQueue: Cancel request while queue is running

I am using ASIHTTPRequest (I know, I know, it is not being maintained - that doesn't matter; it works and it is what my app is built on) to run a series of HTTP requests through ASINetworkQueue.
The problem is that my queue will have many requests (thousands), and it will take a while to run. In the time that it is running, some of the data in the app may have changed which would make some of the request unnecessary. I would like to run a validation method on each request right before it runs, and if the validation method does not check out, then it will cancel that request and go on to the next one.
Right now, I am using the following code to create my ASIHTTPRequests:
ASINetworkQueue *myQueue = [ASINetworkQueue queue];
NSURL *URL = [NSURL URLWithString:#"http://mywebsite.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setStartedBlock:^{
NSLog(#"Request started: %#", request.url.absoluteString);
}];
[request setCompletionBlock:^{
NSLog(#"Request completed: %#", request.url.absoluteString);
// do some code here to clean up since it's finished
}];
[myQueue addOperation:request];
My current thinking is to put something into the startedBlock, so it would do:
[request setStartedBlock:^{
NSLog(#"Request started");
if (![self myValidationMethod]) {
[request cancel]; // <----------
}
}];
However when I do this, I get the following warning from Xcode:
"Capturing 'request' strongly in this block is likely to lead to a retain cycle."
First, is this the right method to go about doing this? I can't seem to find a way to remove a specific ASIHTTPRequest from an ASINetworkQueue. Second, is this warning from Xcode something that I will need to worry about?
About the warning you capture the blocks 'container' and form a cycle... just say:
__weak ASIHTTPRequest *rw = request;
and use that in the block.
as for the started block approach. doesnt sound perfect to me but I dont know a better approach...

how to load xml into memory in faster way?

I am new to objective-c. I load the whole xml string from server to an nsxml parser like below: but the problem is loding from url to memory takes much more time than parsing it. how can i solve that? (my app is very slow)
xmlString = [[NSMutableString alloc] initWithContentsOfURL:url usedEncoding:&NSUTF8StringEncoding error:&error];
NSData *xmlData = [xmlString dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData];
Run your XML Parser in different Thread.(this will not make your parsing faster)
How To Choose The Best XML Parser for Your iPhone Project
Basically NSXMLParser is slow. There is a possibility of finding a better parser for the specific need. A true stream parser might help if you do not need the entire DOM and validation.
Don't use
xmlString = [[NSMutableString alloc] initWithContentsOfURL:url usedEncoding:&NSUTF8StringEncoding error:&error];
Use a network library like ASIHTTPRequest to load the content from a URL and then parse it.
Loading directly from URL like you've done will hang your app till the data is loaded.
Download and install that library as given in the instructions (it's easy), then you can do
{
//in some function
NSURL *url = [NSURL URLWithString:urlString];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous]; //this will load URL in background
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
//parse the XML here
[self parseXML:responseString];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
}
You cannot load the xml faster from the url as it totally depends on your internet connection.
To keep your application smooth, you need to parse the xml in another thread. I answered a similar question in the following url
How to handle freezing programm at loading xml from bad url?
Also there are faster XML parser than the defaul NSXMLParser. There is a good introduction about them in the following blog post. So you can use any of these parser in place of NSXMLParser to improve the performance of your application.
http://www.raywenderlich.com/553/how-to-chose-the-best-xml-parser-for-your-iphone-project
I hope that it may clarify a little bit of your question.

How to load content into TableView without blocking the UI?

I'm working on a TableView which controller downloads data from a web feed, parse and populate its content in this TableView. The feed provides data in chunks of 10 items only. So, for example loading data when there are 112 items could require about 12 requests to server. I would like to make these requests without blocking user screen and it should load data in order, like it can't load items on page 5 unless it has already fetched previous one (1,2,3,4 in this exact order for the example).
Any idea on how to implement this ?
Thx in advance for your help,
Stephane
Make your web calls asynchronous. Dont do web calls on the main UI thread...
For example if you are using ASIHttp library to make http calls (this is built on top of Apple's NSURLConnection), making an async request is as simple as -
NSURL *url = [NSURL URLWithString:#"http://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
And when the data is fetched these selector callbacks are invoked -
- (void)requestFinished:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
// Use when fetching binary data
NSData *responseData = [request responseData];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
}
This will definitely make your UI responsive...
Also keep in mind to update UI elements only on the main thread. It's easy to start updating ui elements from background threads. So keep in mind...
You do not need to use another API and can use Apple's own NSURLConnection. It can retrieve the data synchronously or asynchronously. Of course the latter is necessary in your case. You save the data in the requests's delegate methods.
– connection:didReceiveResponse:
– connection:didReceiveData:
– connection:didFailWithError:
– connectionDidFinishLoading:
Also, see my recent more complete answer to this question.

iOS: ASIHTTPRequst synchronous on background selector bad idea?

I was using NSURLConnection in a synchronous way before running on a background selector, so when I moved over to ASIHTTPRequest I did the same with this framework.
So, is it a bad idea to do something like the following?
// From another method
[self performSelectorInBackground:#selector(callDatasource) withObject:nil];
- (NSData *)callDatasource {
NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:someURLthatIamusing];
[request setTimeOutSeconds:50.0];
[request startSynchronous];
NSError *error = [request error];
NSData *returnedData;
if (!error) {
returnedData = [request responseData];
} else {
// do something with error
}
[self performSelectorOnMainThread:#selector(done) withObject:nil waitUntilDone:NO];
[apool release];
return returnedData;
}//end
What would be the advantage to use the ASIHTTPRequest and asynchronous methods along with the delegate methods?
From experience, sometimes odd things can happen when using ASIHTTPRequest synchronous requests off a secondary thread: the download activity icon in the status bar not disappearing upon download completion is one issue I've noticed from time to time. I've had no major problems in the past, but I use the asynchronous methods now rather than your approach. The ASI asynchronous methods are by the nature of being a widely used library more highly tested than my own implementation could ever be.
There are a number of advantages with using the asynchronous methods - you mention the delegate methods, but the latest release of ASI actually also supports blocks, which is a great leap forward (dealing with multiple synchronous calls used to be a bit of a pain due to the shared delegate methods (or unique delegates for each asynchronous call). But with blocks you can now get rid of the delegates entirely. I've found them to be really useful. Plus if you use multiple contributors it can make readability a lot easier.
Also, by doing it Async, you can more easily track progress through the setProgressDelegate command.