Handling connection restore in iOS
With very few exceptions, mobile Apps connect to services over the Internet to retrieve and send information. Since we have to expect the connection state of mobile devices to change frequently (switching between networks, in-and-out of cell coverage, etc.), responding to connection failures is a very common task. In many of our Apps we’ve found it useful to implement what one might term a reactive-then-proactive pattern for handling connection failure and restore:
- Try to make a connection, for example, to download some data
- In reaction to that connection failing, start monitoring for a change in connection status
- When the connection status changes, if we can connect to our host, then stop monitoring connection status and proactively try the connected-operation again (i.e. go to step 1). If we still can’t connect, keep monitoring for a change in connection status (i.e. stay in reaction mode, and repeat step 3 whenever the connection status changes).
For iOS Apps, we encapsulate this pattern in a utility class which leverages Apple’s Reachability sample and NSNotificationCenter to accomplish the connection status checking, and a block type to allow a consuming object to specify a callback for connection status changes.
The relevant parts of the utility class look like this:
#import "Reachability.h"
typedef void(^ReachabilityChangedBlock)(NetworkStatus status);
@property (readonly, nonatomic, strong) Reachability* hostReachable;
- (void)observeReachabilityChangedUsingBlock:(ReachabilityChangedBlock) block;
// Replace this hostName with whatever host you're connecting to
NSString* hostName = @"www.artermobilize.com"
_hostReachable = [ReachabilityreachabilityWithHostName:hostName];
...
- (void)observeReachabilityChangedUsingBlock:(ReachabilityChangedBlock) block {
[[NSNotificationCenter defaultCenter] addObserverForName:kReachabilityChangedNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
Reachability* reachability = note.object;
if (reachability.currentReachabilityStatus != NotReachable) {
// If we're able to connect, stop observing reachability // changes. The caller can call the method again in // reaction to another connection failure. [[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil];
}
block(reachability.currentReachabilityStatus);
} ];
[_hostReachable startNotifier];
}
Then, the calling code simply needs to supply a block to handle a change in network connection status. For example:
[network observeReachabilityChangedUsingBlock:^(NetworkStatus status) { if(status != NotReachable) { // Perform work after re-connecting, e.g. fetch some data [self fetchSomeData]; } }];