设置 NSZombieEnabled 定位 EXC_BAD_ACCESS 错误

voidxin 2011-10-13

http://unmi.cc/nszombieenabled-locate-exc_bad_access-error,来自隔叶黄莺UnmiBlog

我们做iOS程序开发时经常用遇到EXC_BAD_ACCESS错误导致Crash,出现这种错误时一般Xcode不会给我们太多的信息来定位错误来源,只是在应用Delegate上留下像Thread1:Programreceivedsignal:"EXC_BAD_ACCESS",让问题无从找起。

比如你对已释放的对象发送消息时就会出现,EXC_BAD_ACCESS,再如release的对象再release,release那些autorelease的对象等也会报这样的错。默认设置下Xcode不会给你定位具体是哪一行代码,不该去使用已释放的对象,或者release用错了。

比如UIViewController子类中这样的代码:

static NSMutableArray *array;
 
- (void)viewDidLoad
{
    [super viewDidLoad];
    array = [[NSMutableArray alloc] initWithCapacity:5];
    [array release];
}
 
- (void) viewWillAppear:(BOOL)animated {   
    [array addObject:@"Hello"];
}

上面的代码就会出现EXC_BAD_ACCESS错误,但我执行时Xcode一出错却是定位在我在AppDelegate的application:didFinishLaunchingWithOptions:方法上的某行了,如果代码量多了,要查找具体问题非常难,只能凭经验了。

不过NSZombieEnabled环境变量可以帮我们的忙,就是当设置NSZombieEnabled环境变量后,一个对象销毁时会被转化为_NSZombie,设置NSZombieEnabled后,当你向一个已经释放的对象发送消息,这个对象就不会向之前那样Crash或者产生一个难以理解的行为,而是放出一个错误消息,然后以一种可预测的可以产生debug断点的方式消失,因此我们就可以找到具体或者大概是哪个对象被错误的释放了。

对Xcode设置了NSZombieEnabled之后,Xcode会明确定位在行[arrayaddObject:@"Hello"],然后控制台下报的错误信息是:

***-[__NSArrayMaddObject:]:messagesenttodeallocatedinstance0x6557370

如何设置NSZombieEnabled呢,在Xcode3和Xcode4下设置不一样,Xcode4下设置很简单。

Xcode3下NSZombieEnabled设置方法如下:

1.在XCode左边那个Groups&Files栏中找到Executables,双击其中的一项,或者右键GetInfo;

2.切换到Arguments

3.这里一共有两个框,在下面那个Variablestobesetintheenvironment:点+号添加一项,Name里填NSZombieEnabled,Value填Yes,要保证前面的钩是选中的。

Xcode4下设置NSZombieEnabled的方法:

你可以点击Xcode4菜单Product->EditScheme->Arguments,然后将点击”加号”,将NSZombieEnabled参数加到EnvironmentVariables窗口中,后面的数值写上”YES”.

或者在Xcode4菜单Product->EditScheme->Diagnostics设置窗口中直接勾上EnableZombieObjects即可,Xcode可用cmd+shift+<进到这个窗口。

Xcode4已经考虑到了现在的要求,所以提供了更便捷的设置的方式,你也可以在这个窗口中设置其他一些参数,你肯定能由此获得更多的帮助信息。

另外再说一下,如果没有为Xcode设置NSZombieEnable,像下面的代码或许可以正确执行,打印出你所期望的结果“Hello”.

static NSMutableArray *array;
 
- (void)viewDidLoad
{
    [super viewDidLoad];
    array = [[NSMutableArray alloc] initWithCapacity:5];
    [array release];
    [array addObject:@"Hello"];
    NSLog(@"%@", [array objectAtIndex:0]);
}

但是一旦加上了NSZombieEnable设置,上面的代码行[arrayaddObject:@"Hello"]也将无法投机取巧了,同样会得到错误提示:

***-[__NSArrayMaddObject:]:messagesenttodeallocatedinstance0x6557370

即使该array所指向的内存还是原来的数据也不能逃脱掉NSZombieEnable的法眼。也就是之所以未设置NSZombieEnable时上面代码能得到正确结果,是因为,虽然[arrayrelease]是标记为释放掉该内存块,但是后面使用array时,因为该指针指向的内存数据未被覆盖,所以未出错,这和C++的指针delete后的效果是一样的。

相关推荐