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?
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.