NSURLConnection sendAsynchronousRequest what is considered an error? - ios

I am confused about this method, specially about the error part and the documentation. Here on the documentation it says that
If the request completes successfully, the data parameter of the
handler block contains the resource data, and the error parameter is
nil. If the request fails, the data parameter is nil and the error
parameter contain information about the failure.
The problem is that, I have seen that some http response error codes fall into the "there is an error" and some dont, furthermore I can have data and error at the same time (but supposedly one should be nil at all times according to the documentation).
[NSURLConnection sendAsynchronousRequest:theRequest
queue:[[NSOperationQueue alloc] init]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
For example, my server sends a 401 response if the user uses wrong credentials, and this is cached inside the error clause, but if i send a 409 (duplicate entry) this is NOT cached by it. Im having some issues redirecting the flow because of this, im not sure what this method will consider an error and what it will not.
Also, how do i properly check for this?, I thought that just checking if there is an error, and then checking what was the code of the response would suffice to display a message or take an action, but as I described before, some "error" codes don't necessarily generate the error object. Should i first check for the status code?
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int responseStatusCode = [httpResponse statusCode];
if (responseStatusCode == 200)
{
// If 200, assume everything went well?
} else
{
// Something went wrong, check for the code and the error here?
}

From my experience an error occurs when there is no response at all from the server, that's why the data is 0. If a server returns 400 or 500 error then these are a response from your server and depending on your server code maybe an error message you can parse.

Related

Parse custom value from NSError

When API request fails, I need to know number of failed attempts. Backend has added a property ‘attempts’ to error object. How can I find this value, since NSError is not KV pairing compliant and I don’t see it when I log the error object to console.
If you are using NSURLSession for urlrequest , then you will have delegate methods for NSURLSession responses , they are:
->didReceiveResponse = here you receive the response that urlrequest has completed and response received status
->didReceiveData = here you get the SUCCESS response date for your request
->didCompleteWithError = here you get the FAILURE response (i.e) ERROR callback ,this is called every time when request fails , which gives you error data

NSURLConnection: Confusion with the oder in which connection:didReceiveResponse: and connection:didFailWithError: are called

This may be a very silly question!! But, as I am having a doubt, thought of asking here.
Are the two delegate methods (i.e. connection:didReceiveResponse: and connection:didFailWithError:) are mutually exclusive to each other? I mean is there any scenario in which both the delegate methods could get called by NSURLConnection object?
In case only connection:didFailWithError: gets called, how to retrieve the HTTP status code?
From the docs:
The only case where this message is not sent to the delegate is when
the protocol implementation encounters an error before a response
could be created.
NSURLConnectionDelegate Class Reference
So, a NSURLConnection could fail before it gets a response, however it could fail after. Since connection:didFailWithError ceases any further messages for that connection, the following two scenarios could happen:
The connection is started, fails to get a response and connection:didFailWithError is called.
The connection is started and gets a response, connection:didReceiveResponse: is called, then the connection fails for some reason (The network connection could drop out for example), before connectionDidFinishLoading is called.
You will need to get the HTTP status code from connection:didReceiveResponse, if that method isn't called, there is no status code as it is part of the response. If you need to access it from within connection:didFailWithError you will need to record it.
Note that to get the status code, you will also need to case NSURLResponse to NSHTTPURLResponse like so:
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(#"Status code %ld", httpResponse.statusCode);

nsurlconnection returns no error when

Does
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
return error = nil when data is not nil?
if there is data returned, is error always nil?
that's what the documentation says ...
how is error affected by the http status code?
like if the status code is not 200, does it always return an error?
The NSError is not related with the HTTP Response. The NSError is returned when the connection itself failed. A bad HTTP status code means the request itself works for the client.
You have to manually check the status code.
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int responseStatusCode = [httpResponse statusCode];
Now you can test if the status is 200.
To answer to your questions :
return error = nil when data is not nil?
if there is data returned, is error always nil?
If the data == nil then you should have error != nil
how is error affected by the http status code? like if the status code
is not 200, does it always return an error?
If you got a status code then it means the connection worked (from a connection request point of view, not the HTTP one) so error == nil and data should be not nil
You answered your first two questions yourself already. The documentation is right there.
Regarding the status code: No, status codes do not affect the NSError at all. This NSError is reserved for when a NSURLConnection actually fails in a non-HTTP way. For example when you're actually offline and no request can be made at all. Also keep in mind, that NSURLConnection is not tied to HTTP requests in any way. iOS also supports FTP connections out of the box (no status code like in HTTP here) and you can even write your own protocol support for almost anything you can think of.
Of course there will just occure an NSError if the request failed to get the data. But if the server returns you any other status code than 200, it will be like an error because you couldn't get the data. But by checking the status code you can give more specific error messages to the user instead of just Couldn't load data, because you can specify if there was an NSError which could be caused by missing internet connection or if you received any bad status code and the server is not available..

NSError not being populated

Several times before I used the method...
NSURLResponse *response;
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
to send/receive data synchronously when in an NSOperation and it has worked.
I'm working on a new project (new API, new server) now and the error just isn't being populated.
I'm using Charles proxy to snoop the network traffic and I can see "Response Code 500 Internal Server Error" coming back from the failed request in Charles but in the app the error object is always nil.
Like I said, I've used this loads before and the error is always populated if an error occurs.
Is there something on the server side that I can point out to the server side dev? He's adamant that I must be doing something wrong. The only thing I don't understand is that Charles is picking up response code 500 from it.
N.B. The problem is not that the error is occurring. The problem is that when it does occur the NSError object is not reporting it back to me. Just to clear it up in case anyone tells me to ask the server dev to fix the error. :-)
Your error object is not populated because the request succeeded from NSURLConnection's perspective -- that is, it was able to send data to the server and receive a response.
For protocol-specific errors, you need to inspect the NSURLResponse you get back. In this case, cast the response to NSHTTPURLResponse and invoke -statusCode.
The error is only populated if there is no response from the server or not a valid HTTP response, e.g. connection loss etc.
"Response Code 500 Internal Server Error" means there was an internal server error and your server returns an HTTP message with the response code 500. You should use NSHTTPURLResponse instead of NSURLResponse and call the statusCode method to check the HTTP response code. If the response code starts with 2 everything is fine. So I usually have a check like this: statusCode / 100 == 2.
For more HTTP response codes see http://en.wikipedia.org/w/index.php?title=HTTP_response_codes

iOS - NSURLConnection - Check for URL

I'm using NSURLConnection with sendAsynchronousRequest method (and handing the data in block).
Using above method, I'm downloading a video file from server and saving locally in cache folder.
This is working fine if the URL is valid. If the URL is invalid (that is the video is not available at given URL), it is still saving a file with the file name that I'm giving. NSError is nil and NSData object is not nil. How can I check whether the URL is valid or catch the error if URL is not there?
Check the NSURLResponse in the block, if it is an http request it is really an NSHTTPURLResponse. Check the statusCode to see the HTTP error. It may be a 404, 302, etc.
Also check the returned data, convert it to a string and see if there is anything interesting there. Sometimes there is a redirect in the returned html.

Resources