2

我真的不知道这是怎么发生的。我有一个使用 ARC 的应用程序。我的大多数视图控制器都注册了 NSNotifications。所有注册都在主线程上完成。

当发生内存警告时,用于每个不可见选项卡的导航控制器为 nil'd 并因此被释放。在这种情况下,一个导航控制器及其视图控制器被释放,并且视图控制器在其 dealloc 方法期间使应用程序崩溃。

具体来说,它正在从所有 NSNotificationCenter 通知中删除自己。

dealloc 方法也在主线程中运行,所以我看不出这怎么可能是线程问题。

崩溃的线是-[SearchTabViewController dealloc] (SearchTabViewController.m:44)

代码中的那一行是:[[NSNotificationCenter defaultCenter] removeObserver:self];

实际的崩溃原因似乎是objc_msgSend引用了一个已释放的对象。

问题在于这里只发送了 2 条消息,发送defaultCenterNSNotificationCenter类的消息(它永远不会是无效引用,因为它是一个类)和removeObserver:发送给默认中心对象的消息(也永远不能被释放,因为它是单例)。

唯一引用的其他对象是 self,它还不能被释放,因为我们仍然在那个对象的“dealloc”方法中......基本上这个崩溃不应该发生。

我在这里缺少什么吗?下面是崩溃日志的相关部分:


Exception Type:  SIGSEGV
Exception Codes: SEGV_ACCERR at 0xe0000008
Crashed Thread:  0

Thread 0 Crashed:
0   libobjc.A.dylib                     0x000035b0 objc_msgSend + 16
1   Anghami Beta                        0x000c7473 -[SearchTabViewController dealloc] (SearchTabViewController.m:44)
2   CoreFoundation                      0x00003311 CFRelease + 101
3   CoreFoundation                      0x0000d95d -[__NSArrayM dealloc] + 141
4   Anghami Beta                        0x0033e73f -[EX2NavigationController .cxx_destruct] (EX2NavigationController.m:51)
5   libobjc.A.dylib                     0x00007f3d object_cxxDestructFromClass(objc_object*, objc_class*) + 57
6   libobjc.A.dylib                     0x000050d3 objc_destructInstance + 35
7   libobjc.A.dylib                     0x000053a7 object_dispose + 15
8   UIKit                               0x000cec89 -[UIViewController dealloc] + 1181
9   CoreFoundation                      0x00003311 CFRelease + 101
10  CoreFoundation                      0x0000da13 -[__NSArrayI dealloc] + 79
11  libobjc.A.dylib                     0x00005489 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 169
12  CoreFoundation                      0x00005441 _CFAutoreleasePoolPop + 17
13  CoreFoundation                      0x00095f41 __CFRunLoopRun + 1297
14  CoreFoundation                      0x00008ebd CFRunLoopRunSpecific + 357
15  CoreFoundation                      0x00008d49 CFRunLoopRunInMode + 105
16  GraphicsServices                    0x000052eb GSEventRunModal + 75
17  UIKit                               0x00057301 UIApplicationMain + 1121
18  Anghami Beta                        0x0000334d main (main.m:17)
4

1 回答 1

3

所以事实证明,崩溃日志具有误导性。当连接到启用了僵尸对象的调试器时,我最终能够实现它。崩溃的实际来源是一个加载器对象,它将此控制器作为它的委托,在控制器被释放后试图调用其中一个委托方法。

现在在 dealloc 中,我将加载程序的委托归零并取消加载(如果激活),瞧,不再崩溃。


此外,值得注意的是,这种崩溃拒绝在模拟器中发生,但几乎每次都在设备上发生。因此,在追踪奇怪的内存错误时,不幸的是,Zombies 工具并不总是一个可行的工具,因为它需要应用程序在模拟器中运行。

所以下一个最好的事情是去编辑方案并在那里启用僵尸对象,然后在设备上构建和运行并等待它崩溃。您不会以这种方式获得完整的保留/发布历史记录,但在这种情况下,它可以提供足够的信息来追踪原本难以捉摸的问题。

于 2012-10-16T22:56:20.830 回答