iOS Reachability test

tom picture tom · Jun 15, 2012 · Viewed 8.2k times · Source

For our app, we use the following code to check for internet connection whenever the app user is trying to post a message. When we test the feature, it works fine when turning on the airplane mode. Then when we turn off the airplane mode, the call to connected still returns NO. What could be the reason for that? Do we need extra "setup" in the order in order to get it right? such as listen to network state change notifications?

+ (BOOL)connected 
{
    Reachability *hostReach = [Reachability reachabilityForInternetConnection]; 
    NetworkStatus netStatus = [hostReach currentReachabilityStatus];    
    return !(netStatus == NotReachable);
}

Answer

Kishor Kundan picture Kishor Kundan · Oct 2, 2012

Apple Engineers have suggted that completely relying on Rechability.

From a SO post (source of blockquote)

On a WWDC talk this year the Apple engineer on stage recommended users to never base 
the application internet access on the Reachability example app status. Often     
reachability doesn't provide a complete information (it is based on a complex mechanism)    
and the suggestion provided by the engineer was this:

1. try to do your internet connection, whatever it is the Reachability status; 
   then set your UI hint based on success/fail result
2. if it fails due to networking issue, then register to Reachability and retry again 
   when Reachability gives the green light; this is needed when you want to recover 
   automatically from the fail condition
3. in any case give the user the possibility to "force a retry", whatever is the 
   Reachability status. If it succeeds, reset your UI hint immediately.

What I have done ?

Every time I need to make a connection for example

NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString 
               stringWithFormat:@"http://myadress.com"]]];
[self performSelectorOnMainThread:@selector(responseHandler:)
                       withObject:data waitUntilDone:TRUE];


- (void)responseHandler:(NSData *)responseData {
    if(!responseData) {
       ReachabilityController *reachability = [[ReachabilityController alloc] init];
       [reachability checkReachability];
       return;
    }
   // you handle your data
}

What is happening there is, the reachability will only be tested if the connection was failed. I have made a generic ReachabilityController that only deals with the reachability. I did it so, such that i could make calls from all the other controllers every time i make a request.

My ReachabilityController.m looks like

-(void) checkReachability {
     Reachability* internetAvailable = [Reachability reachabilityForInternetConnection];
     NetworkStatus netStatus = [internetAvailable currentReachabilityStatus];
     NSString *messageText;
     if (netStatus == NotReachable)
     {
         messageText = [NSString stringWithFormat:@"Internet access not available"];
     }
     else
     {
          Reachability *netReach = [Reachability reachabilityWithHostName:host];
          NetworkStatus hostStatus = [netReach currentReachabilityStatus];
          if (hostStatus == NotReachable)
          {
              messageText = [NSString stringWithFormat:@"Host Unreachable"];

          }
          else
          {
              messageText = [NSString stringWithFormat:@"Problem with remote service"];
          }

     }
     NSLog(@"%@", messageText);   
}

It won't crash your app, As you are handling the "nil" data parameter yourself and finally you are determining the cause.

hope this helps!

UPDATE:

Apple may reject your app if you show a false message about the Internet Connectivity. They are very serious about their reputation with the iphone. If the internet connectivity is available but if your app reports that internet connectivity is unavailable, It will be considered very serious