checking reachability against a specific page in a URL

The Reachability class and -reachabilityWithHostname: is designed to be a quick, fail-fast mechanism to determine whether you have basic network connectivity to the host. If you need to verify that a particular URL can be downloaded, you need to be looking at using NSURLConnection to retrieve the contents of the URL in order to verify that it is truly available.

Depending on whether you need to do this in the foreground or background, you can either use the simple-but-blocking:

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error

or you can use the more complicated method of creating an NSURLConnection object, setting up a delegate to receive responses and wait for those responses to come in.

For the simple case:

 NSURL *myURL = [NSURL URLWithString: @"http://example.com/service.asmx"];
 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: myURL];
 [request setHTTPMethod: @"HEAD"];
 NSURLResponse *response;
 NSError *error;
 NSData *myData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];

If you receive back a non-nil myData, you've got some kind of connectivity. response and error will tell you what the server responded to you (in the case of response and if you received a non-nil myData) or what kind of error occurred, in the case of a nil myData.

For the non-trivial case, you can get good guidance from Apple's Using NSURLConnection.

If you don't want to stall your foreground process, you can do this two different ways. The above documentation will provide information on how to implement the delegate, etc. However, a simpler implementation would be to use GCD to send the Synchronous request on a background thread, and then message yourself on the main thread when you are done.

Something like this:

 NSURL *myURL = [NSURL URLWithString: @"http://example.com/service.asmx"];
 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: myURL];
 [request setHTTPMethod: @"HEAD"];
 dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, NULL), ^{
      NSURLResponse *response;
      NSError *error;
      NSData *myData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
      BOOL reachable;

      if (myData) {
            // we are probably reachable, check the response
            reachable=YES;
      } else {
            // we are probably not reachable, check the error:
            reachable=NO;
      }

      // now call ourselves back on the main thread
      dispatch_async( dispatch_get_main_queue(), ^{
            [self setReachability: reachable];
      });
 });

If you want to check reachability against a URL (the one usually used is against a hostname) just do a HEAD request using a NSURLConnection.


Swift 5

A possible solution for Swift is:

 func verifyURL(urlPath: String, completion: @escaping (_ isValid: Bool) ->()) {
    if let url = URL(string: urlPath) {
        var request = URLRequest(url: url)
        request.httpMethod = "HEAD"
        let task = URLSession.shared.dataTask(with: request) { _, response, error in
            if let httpResponse = response {
                if httpResponse.getStatusCode() == 200 {
                completion(true)
                }
            } else {
                completion(false)
            }
        }
        task.resume()
    } else {
        completion(false)
    }
}

Then call the method like that:

verifyURL(urlPath: "www.google.com", completion: { (isValid) in
    if isValid {
        runYourCode()
    } else {
        print("URL: www.google.com is not reachable")
    }
})