21

I need to check whether a URL (represented by a NSURL) is available or returns 404. What is the best way to achieve that?

I would prefer a way to check this without a delegate, if possible. I need to block the program execution until I know if the URL is reachable or not.

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
Erik
  • 11,944
  • 18
  • 87
  • 126

4 Answers4

39

As you may know already that general error can capture by didFailWithError method:

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"Connection failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}

but for 404 "Not Found" or 500 "Internal Server Error" should able to capture inside didReceiveResponse method:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    if ([response respondsToSelector:@selector(statusCode)])
    {
        int statusCode = [((NSHTTPURLResponse *)response) statusCode];
        if (statusCode == 404)
        {
            [connection cancel];  // stop connecting; no more delegate messages
            NSLog(@"didReceiveResponse statusCode with %i", statusCode);
        }
    }
}
jodm
  • 2,607
  • 3
  • 25
  • 40
Jirapong
  • 24,074
  • 10
  • 54
  • 72
  • 7
    Note that there's a handy class method on NSHTTPURLResponse to return a localized description for the error code: `[NSHTTPURLResponse localizedStringForStatusCode: [response statusCode]]` – Jim Dovey Mar 20 '11 at 19:41
  • Is it possible to have this in Swift..? Thank you very much – ernestocattaneo Jan 07 '15 at 15:52
  • 3
    I'm sure you do this in Swift version. Convert by hand would not be difficult. – Jirapong Jan 13 '15 at 03:49
  • @Jirapong: I have few doubts. Which kind of errors are captured in connection: didReceiveResponse: and which are in connection: didFailWithError: ? – Rashmi Ranjan mallick Aug 17 '15 at 02:00
  • @rashmi-ranjan-mallick didFailWithError is the connection cannot connect to server. didReceiveResponse is the connection able to connect but there is status along with it as standard HTTP Status Code. – Jirapong Aug 17 '15 at 03:52
  • Ok!! So, to effectively handle all the errors, I will have to handle it in both delegate methods (connection: didReceiveResponse: and connection: didFailWithError:). Am I correct? My doubt is, in case connection: didReceiveResponse: gets called with a error HTTP status code, will it also call connection: didReceiveData: or connection: didFinishLoading: after that? How should I retrieve the error message from response object? – Rashmi Ranjan mallick Aug 17 '15 at 07:16
29

I needed a solution that didn't use a delegate either, so I took pieces of code shown in other answers here and created a simple method that works well in my case (and might be what you are looking for as well):

    -(BOOL) webFileExists {

        NSString *url = @"http://www.apple.com/somefile.html";

        NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
        NSHTTPURLResponse* response = nil;
        NSError* error = nil;
        [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
        NSLog(@"statusCode = %d", [response statusCode]);

        if ([response statusCode] == 404)
            return NO;
        else
            return YES;
     }
woodmantech
  • 363
  • 3
  • 9
  • 1
    That is not very useful on big files. It will download the entire file before returning a response – Joris Mans Oct 06 '11 at 14:52
  • This works great, thanks. For others looking to do this, you might consider checking for a `200` status code so you know your file is accessible since any number of errors could occur besides a `404` such as `403 Forbidden` and `500 Internal Server Error`. Thanks! – Clifton Labrum Jun 18 '14 at 21:12
8

I used the answer from woodmantech above, but changed it based on what I have seen on other similar questions here so that it does not download the whole file to see if it exists.

I changed NSURLRequest to NSMutableURLRequest, and added:

[request setHTTPMethod:@"HEAD"];

This seems to work fine. I am working on my first app, so no real experience yet. Thanks everyone.

 NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
    [request setHTTPMethod:@"HEAD"];
    NSHTTPURLResponse* response = nil;
    NSError* error = nil;
    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    NSLog(@"statusCode = %d", [response statusCode]);
Javran
  • 3,394
  • 2
  • 23
  • 40
sjw
  • 81
  • 1
  • 1
2

You can achieve a synchronous connection by calling:

NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSHTTPURLResponse* response = nil;
NSError* error = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

Your thread will block until the request has beeen made.

Erik
  • 11,944
  • 18
  • 87
  • 126
  • Synchronous requests block the GUI and also waste resources. Asynchronous does not and allows on top of that better error handling and canceling. – MacMark Apr 18 '12 at 08:02
  • Nope, that's wrong. If nothing is at `url`, it won't block : NSURLConnection will download the content of the 404 webpage. But you can check the status code with `[response statusCode]` – Martin Oct 01 '12 at 12:54
  • @MacMark Why do you assume a synchronous request will block the GUI? What if I've very carefully placed it in an NSOperation that won't? At which point -- to get to my question -- how exactly do they 'waste resources' compared to an asynchronous request? (For that matter, how do they allow for better error handling... unless you use the NSURlConnection protocol instead, which I think you can still do if you really want to, though it's a bit more complicated and if you've already threaded the operation, is completely counterproductive and a waste of resources itself!) – RonLugge Nov 22 '12 at 03:40