Search code examples
iphoneiosobjective-creachability

Reachability hostStatus returning false negative


So, I know there are a lot of posts on here about implementing Reachability, but I cannot find any that answer my specific question.

I'm implementing the following code, but for some reason hostStatus always comes back as NotReachable.

my .h file:

#import <UIKit/UIKit.h>
#import "Reachability.h"

@class Reachability;
@interface ViewController : UIViewController<UINavigationControllerDelegate>{

  Reachability* hostReachable;
  Reachability* internetReachable;

}

@property (nonatomic, assign) BOOL wifiReachable;
@property (nonatomic, assign) BOOL networkReachable;
@property (nonatomic, assign) BOOL internetUsable;

my .m file:

#import "ViewController.h"
#import "Reachability.h"
#import "Reachability.m"

@interface ViewController ()
@end

@implementation ViewController
- (void)viewDidLoad{
  [super viewDidLoad];

  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkStatus:) name:kReachabilityChangedNotification object:nil];

internetReachable = [Reachability reachabilityForInternetConnection];
  hostReachable = [Reachability reachabilityWithHostName:@"www.google.com"];

  [internetReachable startNotifier];
   [hostReachable startNotifier];
  // now patiently wait for the notification
  [self checkNetworkStatus:kReachabilityChangedNotification];

  if(self.internetUsable==TRUE){
    //DO STUFF
  }
  else{
    [self internetAlert];
    //DO OTHER STUFF
  }
}


-(void) checkNetworkStatus:(NSNotification *)notice{


  // called after network status changes
  NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
  NetworkStatus hostStatus = [hostReachable currentReachabilityStatus];
  NSLog(@"%u", hostStatus);
  if(internetStatus==NotReachable){
    NSLog(@"The internet is down.");
    self.internetUsable=FALSE;
  }
  else{
    if(internetStatus==ReachableViaWWAN){
      NSLog(@"The internet is working via WWAN.");
      self.networkReachable=TRUE;
      self.internetUsable=TRUE;
    }
    else if (internetStatus==ReachableViaWiFi) {
      NSLog(@"The internet is working via WIFI.");
      self.wifiReachable=TRUE;
      self.internetUsable=TRUE;
    }
    else{
      self.networkReachable=FALSE;
      self.wifiReachable=FALSE;
      self.internetUsable=FALSE;
      NSLog(@"The internet is NOT useable.");
    }
  }

  if(self.internetUsable==TRUE)
  {

    if(hostStatus==NotReachable)
    {
      self.internetUsable=FALSE;
      NSLog(@"Could not connect to the host");
    }
  }

}

My guess is that it is entering the CheckNetworkStatus method before the hostStatus connection has been properly checked.

Any help would really be appreciated!


Solution

  • You're correct. The problem is that Reachability calls are not synchronous. The method -checkNetworkStatus: is a callback, which means that you don't call it directly. Instead, whenever the system notices that the network reachability has changed, it calls the method itself. As it is, your code is checking the network status immediately after the Reachability objects have been instantiated, and long before they could have got any reply from the network. Remove the -checkNetworkStatus: from -viewDidLoad and you should get the right result.

    (You'll be getting a compiler warning anyway since kReachabilityChangedNotification is a #define of an NSString and not a UINotification anyway - select and right-click and do 'Jump to Definition' to see this - it's in Reachability.h).

    -Side note -make sure you call [[NSNotificationCenter defaultCenter]removeObserver:self name:kReachabilityChangedNotification object:nil]; in -dealloc - you'll get annoying crashes if you forget and the object gets deallocated (this has caught me out before).