我有一个'互联网感知'基类,用于需要在我的应用中建立网络的对象。需要互联网认知的所有对象都从中继承。你可以想象我分配和释放了很多这些对象。
Internet感知基类具有以下代码,用于与用于检查Internet状态的Reachability类进行交互。
#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];
}
只要我的应用中的互联网状态发生变化,应用就会崩溃并出现以下错误:
*** - [Reachability isKindOfClass:]:发送给deallocated的消息 实例0x1e249a30
我打开僵尸并将问题追溯到Reachability.m中的以下代码行
NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
不幸的是,除了停止侦听NSNotifcations并停止通知程序之外,我不确定我的对象可以做些什么来避免此错误。
任何帮助或建议都会很棒。
由于
Vb的
编辑:
好的,按照下面的答案的建议,我用分配的仪器运行它 这是保留计数的历史。
正如我所怀疑的那样,我已解除分配的对象被基金会(即NSNotifcationCenter)调用,而不是我自己。
我的互联网对象有一个指向Reachability对象的强指针。当它们被释放时,Reachability对象也是如此。僵尸是Reachability对象。 在我的互联网对象的dealloc中,我调用了removeObserver,但是基础仍在调用deallocated对象。我不明白为什么......
答案 0 :(得分:6)
基金会仍在发送解除分配的可达性NSNotifcations的原因是因为Reachability对象在与其创建的线程不同的线程上被释放。可达性不是线程安全的。将dispatch_async返回到正在创建Reachability对象的同一队列已解决了该问题。
答案 1 :(得分:3)
当您实例化Reachability并因此持有对Reachability实例的引用的对象在没有(或之前)调用stopNotifier的情况下解除分配时会发生这种情况!
解决这个问题非常简单。在将对象从堆栈中删除之前,必须先调用stopNotifier,然后使用它来拆除Reachability实例。您可以在dealloc方法中执行此操作,或者如果它是viewController,您可以在其中一个生命周期方法(如viewDidDisappear等)中调用它。
这里不应该乱用线程。考虑一下,当你在Reachability上调用startNotifier时,这个东西是通过Reachability的设计在后台线程上开始的。因此,当您调用stopNotifier时,它会为您处理线程。
你不得不搞乱线程的原因在于你的对象持有Reachability的对象被解除分配,但仍然是网络更改的注册监听器,这发生在startNotifier上。当网络发生变化时,猜猜你的对象,虽然仍然注册接收通知,却无处可寻!崩溃的崩溃。 stopNotifier在它死之前取消注册,一切都很好。
- (void)dealloc
{ // self.hostReachability is my property holding my Reachability instance
if (self.hostReachability) {
[self.hostReachability stopNotifier];
}
}
答案 2 :(得分:1)
NSCAssert行是您首次访问解除分配对象的位置,但如果您想了解有关对象生命周期的更多信息,则应使用Instruments。使用Xcode的Profile工具在模拟器中使用Allocations(但不是泄漏!)工具运行程序。在分配工具的启动配置中,启用启用NSZombie Detection 和记录参考计数。当您点击NSCAssert行时,仪器应该检测到向僵尸信息对象发送消息并记下它的尝试。如果您查看僵尸信息对象的详细信息,仪器将向您显示其引用计数的历史记录,您应该能够看到它何时被解除分配。