0

I am using the following method to check if my app has a connection. It's simple and works great for my needs.

+ (void)checkInternet:(connection)block
{
    NSURL *url = [NSURL URLWithString:@"http://www.google.com/"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"HEAD";
    request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
    request.timeoutInterval = 10.0;

    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:
     ^(NSURLResponse *response, NSData *data, NSError *connectionError)
     {
         block([(NSHTTPURLResponse *)response statusCode] == 200);
     }];
}

However, what I'd like to do is if the status doesn't return 200, I'd like to check again, at least a couple of times. What's the best way to do this with 1 second intervals?

Below is how I'm calling the above method.

 [self checkInternet:^(BOOL internet)
    {
         if (internet)
         {
             // "Internet" aka Google
         }
         else
         {
             // No "Internet" aka no Google
         }
    }];
aherrick
  • 19,799
  • 33
  • 112
  • 188

2 Answers2

1

I use Reachability for detecting general network connection issues (See end of answer). I use the following method for executing retries.

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;

You could adapt your system something like the following to have a new class method which has an optional number of retries.

NB. Not tested the following. It is just to give you the general idea.

// Variable to track number of retries left. If you had a shared instance
// a property would be easier.
static NSUInteger maxConnectionTries = 0;

// New method which lets you pass a retry count.
+ (void)checkInternet:(connection)block withMaxTries:(NSUInteger)maxTries
{
   maxConnectionTries=maxTries;
   [self checkInternet:block];
}

// Your original code extended to retry by calling itself when code 200
// is seen on a delay of 1s. Defaults to old code when retry limit exceeded
// or non 200 code received.
+ (void)checkInternet:(connection)block
{
    NSURL *url = [NSURL URLWithString:@"http://www.google.com/"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"HEAD";
    request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
    request.timeoutInterval = 10.0;

    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:
     ^(NSURLResponse *response, NSData *data, NSError *connectionError)
     {
         if ([(NSHTTPURLResponse *)response statusCode] != 200 &&
             maxConnectionRetries > 0){
           maxConnectionRetries--;
           [self performSelector:@selector(checkInternet:) withObject:block afterDelay:1.0]; 
         }
         else{
           maxConnectionRetries = 0;
           block([(NSHTTPURLResponse *)response statusCode] == 200);
         }
     }];
}

For general detection of internet connectivity, it is best to use Reachability. See here.

I start a reachability handler from my AppDelegate code and then publish local notifications when connectivity changes occur. This allows the application to always receive connection change notification and transient view controllers within viewWillAppear and viewWillDisappear to register and deregister for local notifications if they are interested in connection changes.

Rory McKinnel
  • 7,936
  • 2
  • 17
  • 28
  • Thanks for your help here this makes sense! Just to be clear in the If/Else logic, I'd want to retry only if the response code != 200 – aherrick May 12 '15 at 13:00
  • 1
    Ah, I got that wrong. Updated answer so its when != 200 – Rory McKinnel May 12 '15 at 13:04
  • Correct, I was just saying looking at your code example it's coded that way :) – aherrick May 12 '15 at 13:05
  • Hey Rory, this is working awesome! However, is it possible to write the "performSelector" so that it just calls right back into the WithRetries method? I've tried something like this [self performSelector:@selector(checkInternet:withMaxTries:) withObject:block withObject: tries afterDelay:1.0]; – aherrick May 12 '15 at 23:22
  • 1
    The trouble is needing two parameters. You could use `dispatch_after` instead which lets you dispatch a block of code after a period. In here you could the call the withRetries method. See example here on how to dispatch a block with a delay: http://stackoverflow.com/questions/4139219/how-do-you-trigger-a-block-after-a-delay-like-performselectorwithobjectafter – Rory McKinnel May 12 '15 at 23:31
0

FYI here is what I came up with:

+ (void)checkInternet:(connection)block withMaxTries:(NSUInteger)maxTries
{
    NSURL *url = [NSURL URLWithString:@"http://www.google.com/"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"HEAD";
    request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
    request.timeoutInterval = 10.0;

    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:
     ^(NSURLResponse *response, NSData *data, NSError *connectionError)
     {
         if ([(NSHTTPURLResponse *)response statusCode] != 200 &&
             maxTries > 0){

             dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{

                 [self checkInternet:block withMaxTries:maxTries - 1];
             });
        }
         else{
             block([(NSHTTPURLResponse *)response statusCode] == 200);
         }
     }];
}
aherrick
  • 19,799
  • 33
  • 112
  • 188