If your app requires an internet connection for certain tasks you will have to be able to deal with situations where connectivity drops out for some time. For many cases it might be sufficient to display an error when stringWithContentsOfURL returns nil, but it’s better customer service to inform the user beforehand. Apple thinks so too, they test all apps also in airplane mode and your app better not crash or confuse the user or else it will get rejected.
Fortunately there is a great sample on the Apple Website that you might have heard it’s name mentioned in many circles: Reachability. The first version of this was difficult to use but Apple staff keeps polishing their works and so we have reached version 2.2 already, recently updated for iOS 4. The major change that 2.x gave us is the ability to get continuous updates on connection availability. This enables us to have our apps work similar to the iTunes app which displays a message to this effect when there’s no connection and has the UI return as soon as the connection is back.
So, let’s explore how to add the source for Reachability to our project and have some live checks.
First you need to download the latest version of the sample source from the developer website. Here’s the direct link. Click on the “Download Sample Code” button to retrieve the ZIP file.
If you open the sample project you might get “Base SDK missing” if you’re using the latest Xcode and SDK beta. Just switch it to one that you have, by going Project – Edit Project Settings – Base SDK. I use 4.1 at the time of this writing.
From the sample project you need Reachability.h and .m, copy them over to your project. The Reachability class actually wraps up functionality available in the SystemConfiguration.framework and so you need to add a reference to that as well.
There are two ways how you can make use of the Reachability class. The synchronous mode lets you query for the current state, the asynchronous mode sends notifications. Usually you’d want a hybrid solution, because you want a view to look correct for the current network state when it appears as well as react to subsequent changes in reachability. Every instance of Reachability is initialized with a host name that you want to be able to reach.
You can have several running at the same time if your app requires connectivity to seperate hosts. It’s up to you to decide how likely the second host will not be reachable if the first one isn’t. Reachability tests if the host name can be resolved and if there is a TCP/IP path that allows to reach the host. It does not check for the availability of certain web pages. So in all likelyhood you get by with just a single Reachability instance. That’s because not reaching one host usually means that the iPhone does not have internet connectivity.
Here’s the code to demonstrate the use within a view controller:
- (void)configureForNetworkStatus:(NetworkStatus)status { // do something with status switch (status) { case NotReachable: NSLog(@"Not Reachable"); break; case ReachableViaWiFi: NSLog(@"Reachable via WiFi"); break; case ReachableViaWWAN: NSLog(@"Reachable via WWAN"); break; default: break; } } - (void)awakeFromNib { // subscribe to notification [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(reachabilityChanged:) name: kReachabilityChangedNotification object: nil]; // init one watcher, instance variable siteReachability = [[Reachability reachabilityWithHostName:@"www.apple.com"] retain]; // get first status NetworkStatus siteNetworkStatus = [siteReachability currentReachabilityStatus]; // do something with it [self configureForNetworkStatus:siteNetworkStatus]; // start continous updates [siteReachability startNotifier]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [siteReachability release]; // also stops notifier [super dealloc]; } - (void) reachabilityChanged: (NSNotification* )note { // get Reachability instance from notification Reachability* curReach = [note object]; // assert that we actually got Reachability instance NSParameterAssert([curReach isKindOfClass: [Reachability class]]); // get current status NetworkStatus siteNetworkStatus = [curReach currentReachabilityStatus]; // do something with it [self configureForNetworkStatus:siteNetworkStatus]; } |
In this sample I’m initializing everything in the awakeFromNib because I’m getting my view controller from a XIB file.
The code shows how to query a fresh instance for the current status. Then it starts the notifier which will send an NSNotification as soon as the connectivity state changes. As you can see there are three different values to NetworkStatus: no connection at all, site reachable via WiFi, site reachable via WWAN (= cellular data). So you could react differently if you know a big pipe is available as opposed to cellular where people might have limited bandwidth or volume.
Checking for reachability of a specific host is the most practical use case of Reachability. In much rarer cases you might want to check for availability of local WiFi or the internet in general (if you don’t need to access a specific host). Specialized initializers are available for these cases, check the header if you need these.
Enabling your apps for reachability checking is easier than ever. The most difficult part now is to design a nice screen, message or graphic to tell the user that he has to wait until he’s out of the tunnel.
Categories: Recipes