I have an app that uses ASI-HTTP-Request for large files, and I had a tester recently note that they wer observing very long loading delays that should be manifesting as timeouts. I have delegate methods wired up for request failures, but these didn't seem to be happening.
I poured through their documentation but didn't see anything specific.
In ASIHTTPRequest.m, look in the -checkRequestStatus method.
When a timeout occurs, the request fails with an ASIRequestTimedOutError error type:
[self failWithError:ASIRequestTimedOutError];
So you should be able to check the error returned in the delegate's -requestFailed: method:
- (void)requestFailed:(ASIHTTPRequest *)request {
NSLog(#"Error: %#",[[request error] localizedDescription]);
}
It's a good idea to read through the source to get a rough feel for how things work. The documentation is great, but not always in sync with the source code.
Related
How to use ios 5 sdk's asynchronous http get requests to handle redirected urls?
I have found the knowledge in bits and pieces. All the solutions assume some important piece of info to be known to the user. This is very difficult to figure out for a person who who has just started coding ios that to beginning with ios5 sdk.
I know a lot of people might ask to go and read the doc, which somehow have the same issue but please, could someone explain the concept in simple terms...a working code along with the little detail what peice goes where?
Thanks for your time!
AFNetworking provides a good foundation of code for dealing with network requests, and this page specifically has information regarding redirects. It doesn't look like the changes proposed in that comment thread have been committed yet but in any case check it out and see if that helps.
In short, kcharwood suggests subclassing the whichever operation you choose to use and overriding -(NSURLRequest *)connection:willSendRequest:redirectResponse: like so:
- (NSURLRequest *)connection: (NSURLConnection *)inConnection
willSendRequest: (NSURLRequest *)inRequest
redirectResponse: (NSURLResponse *)inRedirectResponse
{
if (inRedirectResponse) {
//Create your mutable request to return in the redirect scenario
} else {
return inRequest;
}
}
I have designed an application which will download some data from the server, and all is working fine if there is no network issue. However if there is some network fluctuation during download some data will not be downloaded and the app will crash.
Here I need some help from you guys. Is it possible for me to write a separate code to handle such situation and re-download the entire data by deleting the incomplete downloaded data.
Thank you in advance,
Yes. you can do that.
There are two situation
1. Network not available.
- -> To fix this you have to use "Rechability" sample code(Provided by Apple). Before start downloading you have to check for internet availability.
- ->Or if you are not checking for internet rechability then you will got error code(404) in delegate method of NSURL connection:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
2. Network Fluctuation.
Here I mean in between downloading if network fluctuate. Then it will call below method
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
You can handle all the things inside this method
When there is any network fluctuation or similar problem, you should get a HTTP error code if you are using NSURLConnection or any other network APIs. You could use that to delete the incomplete downloaded data and inform controller code so it could decide if to redownload etc.
Aditya is right. Assume that you are using NSURLConnection If your connection breaks you can read the response code using the following delegate method,
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int responseStatusCode = [httpResponse statusCode];
}
and you could proceed with stopping the connection and deleting your unfinished download data.
Updated answer for the comment.
If you are using different connections in different classes you should have this implemented in each of the classes. In my opinion you should have a design like in which a particular class will handle all connection related tasks. (May be it won't suit your requirement). But for your current design you should use this in all your classes.
-(void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
}
With in this method one could arrest the error that happened for ex - ("Failed to Connect to iTunes") etc. Now if one wants to show this error message as an alert it would be really helpful for users. Like one example is when the "Failed to Connect to iTunes" error is shown as an UIAlertView, it can lead the user to the problem that his wi-fi was off all this while. He can rectify this problem and retry. But before one chooses to display these errors as UIAlertView, one must know all the possible error values that are returned because a user won't be pleased to see something like "Error %^#)$()(!)#()+! code 123_123443 blah"i.e.something incomprehensible to him. How to best handle this ? As an after thought, it would be nice to know all the possible error messages of NSError thrown in this method.
Thanks in advance
one must know all the possible error
values that are returned because a
user won't be pleased to see something
like "Error %^#)$()(!)#()+! code
123_123443 blah"i.e.something
incomprehensible to him
I don't know all the possible errors that particular method can return but I think it is safe enough to use the localizedDescription method of NSError to present the error to the user.
From Apple docs:
Error objects in the Cocoa domain are
always localized and ready to present
to users, so they can often be
presented without further evaluation.
I have implemented the usual Asynchronous connection mode in one of my apps and it works fine. The error handling is also happening properly. I also have implemented the Reachability API by Apple.
I would like to have for example 5 retires to be done when there is a network failure.
Kindly suggest me a good way to implement this.
Implementing the retry option was simple actually.
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
Use this method to make sure you identify the error condition while a try is failed. You can reinitiate the request again inside this method with a int flag has the NO_MAX_RETRY(eg.5) set.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection this method when returned the connection is successful and you can reset the retry flag and release the retry routine.
I'm following along with this useful looking answer to my question.
It seems to be working, but here are two questions I have:
How do I detect an HTTP error? The didFailWithError method doesn't seem to be getting called?
UPDATE: It considers any response a success. So I guess I have to handle HTTP errors in the didRecieveResponse method, but besides telling the user there was an error when I hit an HTTP error, do I need stop the connection somehow? And/or cleanup?
I see this line in the answer:
[[NSURLConnection alloc] initWithRequest:request delegate:self];
Do I need to release that? Where, how, when?
You will get the status code returned in the didReceiveResponse
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSHTTPURLResponse *httpResponse;
httpResponse = (NSHTTPURLResponse *)response;
int statusCode = [httpResponse statusCode];
//statusCode will be the http code returned like 201,500
}
For stopping the connection, use a class-level variable for the connection. The best way to go about it would be create a wrapper which sends requests and receives response. Make your viewcontroller a delegate of this class and whenever the didReceiveResponse gives an error status code, call the appropriate method of the delegate and stop the connection.
Here's a good wrapper class example
http://kosmaczewski.net/projects/objective-c-rest-client/
Yes, you need to release that object. See the Memory Management Programming Guide for Cocoa. Basically, if you ever create an object with a method name that begins with alloc or new or contains copy, you become an owner of the object and are responsible for freeing it later. Only in the case where you know you're going to need the object up until program termination is it ok not to free it, in which case the operating system reclaims the memory when your app terminates.
If you only need the object within a small scope, you can send it the autorelease message. This will add it to the autorelease pool. The autorelease pool periodically sends a release message to each object in it. It's kind of complicated; see the section on autorelease pools. For example:
In this case, though, because NSURLConnections are asynchronous, autoreleasing won't work. You don't know exactly when it's going to call back into your object with data, so you want to make sure the object hasn't been released yet. The only way to be sure is to know exactly when you're done with the object, and then send it a release message yourself.
All of the various init* functions return a pointer to the given object, so you can just do:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
...
// when done with connection:
[connection release];
Answering the question in your "update"...
Immediately autorelease the NSURLConnection. The connection object is retained by the NSRunLoop (to which it adds itself automatically unless you use the startImmediately:NO constructor). It will get automatically removed from run loop (and hence dealloc'd) on error or finish.