【问题标题】:Reachability causes crash after no network situation -- how to properly use Reachability asynchronously无网络情况下可达性导致崩溃——如何正确异步使用可达性
【发布时间】:2011-05-05 15:18:55
【问题描述】:

我在开发 iPhone 应用时遇到了一个非常奇怪的崩溃。似乎每次我向朋友展示我的应用程序时它都会崩溃,但否则它永远不会崩溃。在对墨菲定律方面普遍感到困惑之后,我确定了撞车的模式——纽约市地铁。使用地铁后,我的应用程序经常崩溃。我已经将问题追溯到我对Reachability 的使用。该应用程序在无网络情况下(不包括飞行模式)使用后下次崩溃。在执行任何其他网络操作之前​​,我正在遵循 Apple 的指导方针并检查与 Reachability 的连接,但我发现了一些关于如何调用它的相互矛盾的文档。

目前我正在做这样的事情:

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

这是基于Reachability Guide for iOS 4的代码

我的问题:是否可以正确使用 Reachability 来解决此错误并处理缺少 3G 或 Wifi 网络的情况?我是否需要生成另一个线程或做一些事情来删除同步调用?

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

应用特定信息: (应用名称)未能及时恢复 已用总 CPU 时间(秒):3.280(用户 1.770,系统 1.510),33% CPU 已用应用程序 CPU 时间(秒):0.040,0% CPU 线程 0 名称:调度队列: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 系统配置 0x311b4256 __SCNetworkReachabilityGetFlags + 962 7 系统配置 0x311b4f1e SCNetworkReachabilityGetFlags + 98

【问题讨论】:

    标签: iphone reachability


    【解决方案1】:

    在同步情况下,您可能会被 iOS 应用程序看门狗杀死。这是因为要进行可达性检查,SCNetworkReachability 功能需要进行 DNS 查找,这可能需要 30 秒。如果检查主线程的可达性(即在 viewDidAppear 中)您可能会阻塞主线程很长时间,iOS 会认为您的应用已挂起,应用程序看门狗会在 20 秒后将其杀死。

    Apple 甚至在 Reacahbility 示例代码中对此提出警告:

    Apple Reachability Sample Code README

    只需像在 Reachability 示例应用程序中那样使用通知 --- 它运行良好,并且在您了解 NSNotificationCenter 设计模式后非常简单。

    祝你好运!

    【讨论】:

    • 谢谢——所以如果主线程被杀死,那会和我同步检查时看到的一致吗? (应用程序在同步检查可达性后下一次运行时崩溃)
    【解决方案2】:

    我通过将其设置为异步解决了我的问题。我调用这样的方法

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

    使用与上述相同的可访问代码。

    我想说总是像这样使用可达性——Apple 给出的例子是不完整的。我已经在一个完整的应用程序上运行了几个月的代码,它非常稳定。

    编辑: 从 iOS 5 开始,此代码不再稳定——它现在有时会由于“超出允许时间的活动断言”而崩溃。自从我写了这个问题以来,Apple 已经更新了他们的文档和示例代码,所以我建议点击另一个答案中的链接。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多