3

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?

Brian Gesiak
  • 6,648
  • 4
  • 35
  • 50

2 Answers2

4

check this function:

- (BOOL)isNetworkAvailable
{
CFNetDiagnosticRef diag;        
diag = CFNetDiagnosticCreateWithURL (NULL, (__bridge CFURLRef)[NSURL URLWithString:@"www.apple.com"]);



CFNetDiagnosticStatus status;
status = CFNetDiagnosticCopyNetworkStatusPassively (diag, NULL);        

CFRelease (diag);

if ( status == kCFNetDiagnosticConnectionUp )
{
    //NSLog (@"Connection is up");
    return YES;
} else {
    NSLog (@"Connection is down");
    return NO;

}
}

This will work just fine..

ThePunisher
  • 410
  • 1
  • 4
  • 14
2

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.

Tom van der Woerdt
  • 29,532
  • 7
  • 72
  • 105
  • Could you please explain how you can definitively state that the second method only checks whether a connection is possible? Is this stated in the documentation somewhere? If you could give me a source I will mark this as the correct answer. – Brian Gesiak Jul 03 '12 at 16:13
  • Any I/O activity either has to be blocking or asynchronous to tell you whether it can or cannot do something. In your example code, you show that it's synchronous and instantly returns. The logical conclusion is that there's no I/O involved. – Tom van der Woerdt Jul 03 '12 at 16:16
  • Could it be that the difference isn't between `SCNetworkReachabilityCreateWithName` and `SCNetworkReachabilityCreateWithAddress`, but rather that `reachabilityForInternetConnection` checks against a socket address of zero, thereby skipping the time-intensive task of checking against a remote host? I just want a logical explanation, here. – Brian Gesiak Jul 03 '12 at 19:17
  • To be honest I'm more of a practical person. The first one checks whether it actually works, the second one takes a guess based on some locally cached info. Isn't that all you need to know? – Tom van der Woerdt Jul 03 '12 at 21:33
  • Good enough for me, I guess. I mean, you could always just attach a fail block to the request itself, anyway. – Brian Gesiak Jul 03 '12 at 22:36