我已经调试了一天左右的iOS应用程序,尝试解决EXC_BAD_ACCESS(SIGSEGV)崩溃问题。
这是崩溃日志中有趣的部分:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x00000051
Triggered by Thread: 0
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x38bfc6e4 __kill + 8
1 myApp 0x002e3ca0 CLSSignalHandler + 192
2 libsystem_platform.dylib 0x38c61060 _sigtramp + 40
3 UIKit 0x306416a2 -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:] + 310
4 UIKit 0x306417d0 __85-[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:]_block_invoke + 104
5 UIKit 0x306416e2 -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:] + 374
6 UIKit 0x30641af2 -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:] + 30
7 UIKit 0x308d84b8 __UIViewWasRemovedFromSuperview + 184
8 UIKit 0x30640bae -[UIView(Hierarchy) removeFromSuperview] + 266
9 UIKit 0x30643402 -[UIView dealloc] + 362
10 CoreFoundation 0x2de00650 CFRelease + 552
11 CoreFoundation 0x2de0bb40 -[__NSArrayM dealloc] + 152
12 libobjc.A.dylib 0x38649b06 objc_object::sidetable_release(bool) + 170
13 libobjc.A.dylib 0x3863b002 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 354
14 CoreFoundation 0x2de0397c _CFAutoreleasePoolPop + 12
15 UIKit 0x3063b248 _wrapRunLoopWithAutoreleasePoolHandler + 32
16 CoreFoundation 0x2de9b1ca __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 18
17 CoreFoundation 0x2de98b6c __CFRunLoopDoObservers + 280
18 CoreFoundation 0x2de98eae __CFRunLoopRun + 726
19 CoreFoundation 0x2de03c22 CFRunLoopRunSpecific + 518
20 CoreFoundation 0x2de03a06 CFRunLoopRunInMode + 102
21 GraphicsServices 0x32af727e GSEventRunModal + 134
22 UIKit 0x306a7044 UIApplicationMain + 1132
23 myApp 0x000c4640 main (main.m:14)
24 myApp 0x000ac31c start + 36
不幸的是,NSZombieEnabled没有用,因为在设置崩溃时崩溃不再发生。
从我的研究中我发现:
release
消息时不记录任何内容在将问题的根源缩小到1级之后,我查看了变量和属性的分配和释放。我在viewDidLoad
中找到了这个:
MyView *view = [[MyView alloc] initWithFrame:CGRectMake(...)];
[_tableView addSubview:view]; // _tableView is an outlet variable
_refreshHeaderView = view; // _refreshHeaderView is a class variable, not a property
[view release];
和viewDidUnload
:
[_refreshHeaderView release];
_refreshHeaderView = nil;
我将_refreshHeaderView = view;
更改为_refreshHeaderView = [view retain];
,现在应用程序不再崩溃。
我不太确定这是正确的解决方案,虽然崩溃不再发生,所以我有这些问题的原因:
view
已初始化,其RC = 1 view
被添加为_tableView
RC = 2 _refreshHeaderView
指向与view
view
已发布RC = 1 _tableView
将释放view
RC = 0 _refreshHeaderView
时,应用程序崩溃_refreshHeaderView = [view retain];
和[_refreshHeaderView release];
或_refreshHeaderView = view;
和不 [_refreshHeaderView release];
感谢您的帮助。
答案 0 :(得分:0)
第1点的摘要对我来说是正确的。
不要将AutoReleasePools与ARC混淆 - AutoReleasePools就像Java中的垃圾收集器。如果需要,可以显式创建AutoReleasePool,但始终使用运行循环建立隐式池。迁移到ARC可能需要更改代码(并且需要不同地使用AutoRelease)。
有关NSZombies的信息在this answer。基本上你应该得到一个日志,如果你发布一个参考数为0的NSZombie。我不知道为什么你没有看到警告。
_refreshHeaderView = [view retain]; and [_refreshHeaderView release];
更好,因为您的对象持有对象的引用,因此需要管理引用计数。