没有网络情况下,可达性导致崩溃 - 如何正确异步使用可达性。

7
我在开发iPhone应用时遇到了一个非常奇怪的崩溃问题。似乎每次我向朋友展示我的应用程序时,它都会崩溃,但是在其他情况下它从未崩溃过。在被这种“墨菲定律”的神秘感所困扰之后,我已经确定了崩溃的模式——纽约市地铁。每次使用地铁后,我的应用程序都会崩溃。我追踪到问题出在我的使用Reachability上。在没有网络连接的情况下(不包括飞行模式),应用程序在下一次使用时崩溃。我正在遵循Apple的指导方针,并在执行任何其他网络操作之前检查连接是否可达,但我找到了一些关于如何调用它的冲突文档。
目前我正在做类似于这样的事情:
-(BOOL)reachable {
    Reachability *r = [Reachability reachabilityWithHostName:@"www.stackoverflow.com"];
    NetworkStatus internetStatus = [r currentReachabilityStatus];
    if(internetStatus == NotReachable) {
        return NO;
    }
    return YES;

我正在使用从viewDidAppear调用的方法同步调用它。

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

这段代码基于iOS 4的Reachability Guide

我的问题是:是否有适当的使用Reachability来处理这个错误并处理3G或Wifi网络的缺失?我需要创建另一个线程或执行一些操作来删除同步调用吗?

顺便说一下,这是我在应用程序崩溃时看到的崩溃日志,这让我认为这是一个同步/异步问题。

应用程序特定信息:
(app name)无法及时恢复
经过的总CPU时间(秒):3.280(用户1.770,系统1.510),33%CPU 经过的应用程序CPU时间(秒):0.040,0%CPU
线程0名称:Dispatch队列:com.apple.main-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
2个回答

5
在同步情况下,您可能会被iOS应用程序看门狗关闭。这是因为为了进行可达性检查,SCNetworkReachability功能需要进行DNS查找,这可能需要长达30秒的时间。如果在主线程上检查可达性(即在viewDidAppear中),您可能会阻塞主线程很长时间,iOS认为您的应用程序已挂起,应用程序看门狗在20秒后将其关闭。
苹果甚至在可达性示例代码中警告了这一点: Apple Reachability Sample Code README 只需像在可达性示例应用程序中一样使用通知-它运行良好,并且一旦掌握了NSNotificationCenter设计模式,就相当简单。
祝你好运!

谢谢 - 所以如果主线程被杀死,那么当我同步检查它时看到的情况是否与我看到的一致?(应用程序在同步检查可达性后下一次运行崩溃) - Mark Chackerian

-1

我通过将它设置为异步来解决了我的问题。我像这样调用一个方法

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSTimer *timer = [NSTimer timerWithTimeInterval:0 target:self selector:@selector(loadData) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[pool release];

而被调用的方法看起来像这样

- (void)loadData {
    // check for reachability first before starting data load
    if ([self reachable]== NO) {
        // display error message that there is no internet connection, e.g.
        UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:@"Connection Error" message:@"Cannot load data.  There is no internet connection." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Retry",nil];
        [errorAlert show];
        [errorAlert release];
    } else {
        // do something to load data from internet ...      
    }

}

使用与上述可达代码相同。

我会建议始终如此使用Reachability -- 苹果提供的示例不完整。我已经将此代码运行在一个完成的应用程序上几个月了,它非常稳定。

编辑: 自iOS 5以来,此代码已不再稳定--它现在有时会由于“超出允许时间的活动断言”而崩溃。自我写这个问题以来,苹果已更新了他们的文档和示例代码,因此我建议按照另一个答案中的链接进行操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接