Search code examples
objective-ciosreachability

How to check for network reachability on iOS in a non-blocking manner?


In my iOS project, I would like to display a message to the user to connect to the internet before certain network operations, so I wrote the following check using Apple's Reachability class:

Reachability *reach = [Reachability reachabilityWithHostName:@"google.com"];
if([reach currentReachabilityStatus] == NotReachable) {
    // ...prompt user to establish an internet connection
} else {
    // ...send an asynchronous request with a timeout
}

However, this had one very big problem--when the device was on a very lossy network (for example, when uplink packet loss is set to 100% on OS X Lion's Network Link Conditioner), [Reachability reachabilityWithHostName:@"google.com"] would block the main thread for 30 seconds before determining a connection was not available. The following code, however, does not block:

if([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] == NotReachable) {
    // ...prompt user to establish an internet connection
} else {
    // ...send an asynchronous request with a timeout
}

Looking at the implementation of Reachability shows that both of these methods use SystemConfiguration.framework, but the first method uses SCNetworkReachabilityCreateWithName while the second uses SCNetworkReachabilityCreateWithAddress. Why does the first method block, while the second does not? Is the second method a good way to check for connectivity? Or is there a better way?


Solution

  • The first one tests whether it can reach google.com, while the second one simply checks whether there's any internet connection possible (which it thinks there is, even though there's packet loss).

    Basically just put it in a thread or in a background queue. The only way to reliably know whether you have a good connection is to test it, and any test is going to be blocking or asynchronous. You simply can't have it instantly available, ever.