iPhone: Detecting Network Status

If you write an iPhone application that uses the network, then you must check if the network is both operating and that your server is reachable. Apple has and will continue to reject applications that do not test reachability. To this end, Apple provides iPhone developers a sample application and class, Reachability, that can easily be used to perform these tests.

Open the Reachability/Classes directory and grab the Reachability.h and Reachability.m files from the Xcode project and copy them onto your Desktop (or any convenient location). This is the Reachability class that we want to reuse in our projects. To use the Reachability class in a project, you must do the following after you create the project in Xcode:

  • Add the header and implementation files to your Classes group (or any convenient location)

  • The Reachability class actually wraps up functionality available in the SystemConfiguration.framework and so you need to add a reference to that. In order to add a framework reference to the project, we need to navigate to the Build Phases tab of the project settings. If you have a code file open, click on the name of your project on the left to get to the project settings. If you have set up custom targets you will want to ensure that you select the target for which you want to add a reference. Under the build phases tab for your selected target there should be a section called Link Binary With Libraries. (If you do not see this section you can click the Add Build Phase button in the lower right and add it.) In this instance you can see that we already have references to UIKit, Foundation and CoreGraphics. To get the reference to MapKit that we need for our project you will have to expand the section and then click on the small ‘+’ symbol in the bottom left corner of the section.

  • Once you’ve done that a list of pre-existing frameworks list will show up and yes you need go hunting for the SystemConfiguration.framework. Now just click ‘Add’ when done and your project is now complete and should be functional with the Reachability API added.
Framework

There are two ways to make use of Apple’s Reachability code:

  • Synchronously, the simpler of the two approaches, the synchronous mode lets you query for the current state
  • Asynchronously, slightly more complicated, but using the Reachability class in this way means your application can be notified of changes in the current network status. The asynchronous mode sends notifications.

Synchronous reachability

Let’s implement the reachability test in the appDelegate. First add the following code to appDelegate.h.

#import "Reachability.h"
 
@interface AppDelegate : UIResponder <UIApplicationDelegate> {
  NSString *internetReachability;
  BOOL gotInternet;
}
 
// Existing code
 
-(BOOL)checkInternet;
 
@end

In the main of the appDelegate, we add a custom method to handle the work.

#pragma mark -
#pragma mark Verbinding controleren
 
// Existing code
 
-(BOOL)checkInternet{
    // Test Internet Connection
    NSLog(@"----");
    NSLog(@"Verbinding controleren");
 
    Reachability *r = [Reachability reachabilityWithHostName:@"http://www.domain.com"];
    NetworkStatus internetStatus = [r currentReachabilityStatus];
 
    BOOL internet;
    if ((internetStatus != ReachableViaWiFi) && (internetStatus != ReachableViaWWAN)) {
        internet = NO;
    } else {
        internet = YES;
    }
 
    return internet;
}

Add it to the didFinishLaunchingWithOptions.

gotInternet = [self checkInternet];
if (gotInternet == 0) {
  NSLog(@"Geen internet verbinding aanwezig");
  UIAlertView *netError = [[UIAlertView alloc]
  initWithTitle:@"Foutmelding"
  message:@"Geen internet verbinding aanwezig"
  delegate:self
  cancelButtonTitle:@"OK"
  otherButtonTitles:nil];
  [netError show];
  [netError release];
} else {
  NSLog(@"Internetverbinding aanwezig");
}

If you are using Apple’s LLVM compiler and their Reachability.h file you may be getting warnings like this:

Reachability.h: warning: Semantic Issue: Declaration of ‘struct sockaddr_in’ will not be visible outside of this function

Add this import line to the includes section of the Reachability.h file:

#import <netinet/in.h>

Asynchronous reachability
You can also use the Reachability classes along with NSNotifications to asynchronously determine reachability.
First add the following code to the .h file of where you are implementing the code (for example ViewController.h).

@class Reachability;
 
@interface ViewController : UIViewController<UIWebViewDelegate> { UIWebView *webView;
    Reachability* internetReachable;
    Reachability* hostReachable;
}
 
@property BOOL internetActive;
@property BOOL hostActive;
 
-(void)checkNetworkStatus:(NSNotification *)notice;
 
@end

Add #import "Reachability.h" to the .m file where you are implementing the check (for example ViewController.m).
In the .m file of where you are implementing the check, you can place this in one of the first methods called (init, viewWillAppear, viewDidLoad, etc.):

@synthesize internetActive;
@synthesize hostActive;
 
-(void) viewDidLoad {
  // check for internet connection
  [[NSNotificationCenter defaultCenter] 
  addObserver:self 
  selector:@selector(checkNetworkStatus:) 
  name:kReachabilityChangedNotification 
  object:nil];
 
  internetReachable = [[Reachability reachabilityForInternetConnection] retain];
  [internetReachable startNotifier];
 
  // check if a pathway to your host exists
  hostReachable = [[Reachability reachabilityWithHostName: @"www.domain.com"] retain];
  [hostReachable startNotifier];
 
  // now patiently wait for the notification
}
 
- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
 
// called after network status changes
- (void)checkNetworkStatus:(NSNotification *)notice {
 
    NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
 
    switch (internetStatus) {
        case NotReachable: {
            NSLog(@"The internet is down.");
            self.internetActive = NO;
            break;
        }
        case ReachableViaWiFi: {
            NSLog(@"The internet is working via WIFI.");
            self.internetActive = YES;
            break;
        }
        case ReachableViaWWAN: {
            NSLog(@"The internet is working via WWAN.");
            self.internetActive = YES;
            break;
        }
    }
 
    NetworkStatus hostStatus = [hostReachable currentReachabilityStatus];
 
    switch (hostStatus) {
        case NotReachable: {
            NSLog(@"A gateway to the host server is down.");
            self.hostActive = NO;
 
            UIAlertView *netError = [[UIAlertView alloc]
            initWithTitle:@"Foutmelding"
            message:@"Geen internet verbinding aanwezig"
            delegate:self
            cancelButtonTitle:@"OK"
            otherButtonTitles:nil];
            [netError show];
            [netError release];            
            break;
        }
        case ReachableViaWiFi: {
            NSLog(@"A gateway to the host server is working via WIFI.");
            self.hostActive = YES;
            break;
        }
        case ReachableViaWWAN: {
            NSLog(@"A gateway to the host server is working via WWAN.");
            self.hostActive = YES;
            break;
        }
    }
}

Leave a Reply