Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reachability causes crash after no network situation -- how to properly use Reachability asynchronously

I was encountering a very strange crash with my iPhone app in development. It seemed that every time I'd show my app to a friend it would crash, but it would never crash otherwise. After being generally mystified by the Murphy's Law aspect, I've determined the pattern of crashes -- the New York City subway. My app crashes consistently after I use the subway. I've traced the problem to my use of Reachability. The app crashes the next time after it is used in a no network situation (not including airplane mode). I'm following Apple's guidelines and checking for for a connection with Reachability before I do any other network operations, but I've found some conflicting documentation about how to call it.

Currently I'm doing something like this:

-(BOOL)reachable {
    Reachability *r = [Reachability reachabilityWithHostName:@"www.stackoverflow.com"];
    NetworkStatus internetStatus = [r currentReachabilityStatus];
    if(internetStatus == NotReachable) {
        return NO;
    }
    return YES;

}

which I'm calling synchronously with a method called from viewDidAppear.

    if ([self reachable]== YES) {
        ... do network stuff ...

which is based on the code from Reachability Guide for iOS 4

My question: is there proper use of Reachability that will take care of this error and handle the absence of a 3G or Wifi network? Do I need to be spawning another thread or do something to remove a synchronous call?

Here, by the way, is the crash log that I see when my app crashes, which leads me to think that it's a synchronous/asynchronous problem.


Application Specific Information:
(app name) failed to resume in time

Elapsed total CPU time (seconds): 3.280 (user 1.770, system 1.510), 33% CPU 
Elapsed application CPU time (seconds): 0.040, 0% CPU

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0:
0   libsystem_kernel.dylib          0x30747fbc kevent + 24
1   libsystem_info.dylib            0x30abec4e _mdns_search + 586
2   libsystem_info.dylib            0x30abfb72 mdns_addrinfo + 370
3   libsystem_info.dylib            0x30abfd68 search_addrinfo + 76
4   libsystem_info.dylib            0x30ac1bcc si_addrinfo + 1080
5   libsystem_info.dylib            0x30abd0b2 getaddrinfo + 78
6   SystemConfiguration             0x311b4256 __SCNetworkReachabilityGetFlags + 962
7   SystemConfiguration             0x311b4f1e SCNetworkReachabilityGetFlags + 98
like image 636
Mark Chackerian Avatar asked May 05 '11 15:05

Mark Chackerian


1 Answers

In the synchronous case, you're probably being killed by the iOS Application Watchdog. That's because to do the reachability check, the SCNetworkReachability functionality needs to do a DNS lookup which can take up to 30 seconds. If check reachability on the main thread (i.e., in viewDidAppear) you block the main thread for a potentially long time, iOS thinks your app is hung and the application watchdog kills it after 20 seconds.

Apple even warns about this in the Reacahbility sample code:

Apple Reachability Sample Code README

Just use notifications like in the Reachability sample app --- it works well and is pretty straightforward once you grok the NSNotificationCenter design pattern.

Good luck!

like image 114
Joel Avatar answered Oct 03 '22 15:10

Joel