Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Reachability sample app stall here?

Apple's sample app named Reachability shows how to detect connections. If you have only wifi but not internet, the app stalls for over a minute on the second line below:

SCNetworkReachabilityFlags reachabilityFlags;
BOOL gotFlags = SCNetworkReachabilityGetFlags(reachabilityRef, &reachabilityFlags);

SCNetworkReachabilityGetFlags comes from SystemConfiguration.framework. Any suggestions on how to get around this?

like image 631
4thSpace Avatar asked Apr 06 '09 22:04

4thSpace


1 Answers

To answer your question directly, no, there doesn't seem to be any way to "get around" SCNetworkReachabilityGetFlags() taking a long time to return under the specific circumstances you described (e.g., checking remote host reachability via WiFi connection to a router with no Internet). A couple of options:

OPTION 1. Make the call in a separate thread so that the rest of your app can keep running. Modify ReachabilityAppDelegate.m as follows for an example:

// Modified version of existing "updateStatus" method
- (void)updateStatus
{
    // Query the SystemConfiguration framework for the state of the device's network connections.
    //self.remoteHostStatus           = [[Reachability sharedReachability] remoteHostStatus];
    self.remoteHostStatus = -1;
    self.internetConnectionStatus   = [[Reachability sharedReachability] internetConnectionStatus];
    self.localWiFiConnectionStatus  = [[Reachability sharedReachability] localWiFiConnectionStatus];
    [tableView reloadData];

    // Check remote host status in a separate thread so that the UI won't hang
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSTimer *timer = [NSTimer timerWithTimeInterval:0 target:self selector:@selector(updateRemoteHostStatus) userInfo:nil repeats:NO];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    [pool release];
}
// New method
- (void) updateRemoteHostStatus
{
    self.remoteHostStatus = [[Reachability sharedReachability] remoteHostStatus];
    [tableView reloadData];
}

OPTION 2. Use a different API/function that uses a timeout value when trying to connect to the remote host. That way your app would only hang for X seconds before it gives up.

Some other things to note:

  • The specific call to SCNetworkReachabilityGetFlags() that you're asking about (i.e., line ~399 in Reachability.m) is trying to see if www.apple.com is "reachable" to deduce if "the external internet" is "reachable" in general.
  • In Apple's System Config framework "reachable" might not mean what you think it does. According to the official docs, "reachable" seems to mean that, in theory, your computer could connect to host X if it wanted to, but it might need to actually establish a connection first (e.g., dial a modem first). In other words, SCNetworkReachabilityGetFlags() doesn't actually establish a connection.
like image 65
Clint Harris Avatar answered Oct 18 '22 19:10

Clint Harris