代码之家  ›  专栏  ›  技术社区  ›  BYZZav

可达性类导致程序崩溃-不确定原因

  •  5
  • BYZZav  · 技术社区  · 12 年前

    我有一个“互联网感知”基类,用于在我的应用程序中需要联网的对象。所有需要具有互联网意识的对象都继承自它。正如你可以想象的那样,我分配和释放了很多这样的对象。

    互联网感知基类具有以下代码,用于与用于检查互联网状态的可达性类进行交互。

    #import "Reachability.h"
    
    - (id) init {
        ...
        self.internetReachable = [Reachability reachabilityForInternetConnection];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkStatus) name:kReachabilityChangedNotification object:nil];
        [self.internetReachable startNotifier];
        ...
      }
    - (void)  dealloc
     {
        [self.internetReachable stopNotifier];
        [[NSNotificationCenter defaultCenter] removeObserver:self];
     }
    

    一旦我的应用程序中的互联网状态发生变化,应用程序就会崩溃,并出现以下错误:

    ***-[可达性isKindOfClass:]:发送到已解除分配的消息 实例0x1e249a30

    我打开了僵尸,并在Reachability.m中追踪到了以下代码行中的问题

    NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
    

    不幸的是,除了停止侦听NSNotifces和停止通知程序之外,我不确定我的对象还能做些什么来避免这个错误。

    任何帮助或建议都将非常好。

    谢谢

    电压b

    编辑:

    好的,所以按照下面答案的建议,我在有分配的工具中运行它 这就是保留计数历史。

    enter image description here

    正如我所怀疑的,这是一个我已经处理的对象,由基金会(即NSNotifcationCenter)调用,而不是我自己。

    我的互联网对象有一个指向可达性对象的强指针。当它们被释放时,Reachability对象也是如此。僵尸是可达性对象。 在我的互联网对象的dealloc中,我调用了removeObserver,但foundation仍在调用deallocated对象。我不明白为什么。。。

    3 回复  |  直到 12 年前
        1
  •  7
  •   BYZZav    12 年前

    Foundation仍在向NSNotifces发送已解除分配的可达性的原因是,Reachability对象是在不同的线程上解除分配的,而不是在其创建的线程上。可达性不是线程安全的。使用dispatch_async返回到创建Reachability对象的同一队列已经解决了这个问题。

        2
  •  4
  •   SmileBot    10 年前

    当您创建的实例化可达性的对象(因此包含对可达性实例的引用)在没有(或之前)调用stopNotificationer的情况下被释放时,就会发生这种情况!

    解决这个问题非常简单。在您的对象从堆栈中删除并用它拆除Reachability实例之前,您必须调用stopNotifier。您可以在dealloc方法中执行此操作,或者如果它是一个viewController,您可以在一个生命周期方法中调用它,如viewDidDisappear等。

    这里应该不需要打乱线程。考虑一下,当您在可达性上调用startNotificationer时,这件事是通过可达性的设计在后台线程上启动的。所以,当您调用stopNotifier时,它会为您处理线程。

    您不得不处理线程的原因与这样一个事实有关,即您持有对可达性的引用的对象已被释放,但仍然是网络更改的注册侦听器,这发生在startNotificationer中。当网络发生变化时,你猜怎么着,你的对象虽然仍然注册接收通知,但却找不到了!Crashy崩溃。stopNotifier在它死之前注销它,一切都很好。

    - (void)dealloc
    { // self.hostReachability is my property holding my Reachability instance
        if (self.hostReachability) {
            [self.hostReachability stopNotifier];
        }
    }
    
        3
  •  2
  •   Aaron Golden    12 年前

    NSCAssert行是您首先访问已释放对象的地方,但如果您想了解更多关于对象生命周期的信息,则应该使用Instruments。使用Xcode的Profile工具在模拟器中使用Allocations(但不是leaks!)工具运行程序。在分配工具的启动配置中,启用启用NSZombie检测 记录引用计数。当你点击NSCAssert行时,Instruments应该检测到向僵尸信息对象发送消息的尝试,并记下它。如果你查看僵尸信息对象的详细信息,Instruments将向你显示其引用计数的历史记录,你应该能够看到它是何时被释放的。