1、使用僵尸变量(NSZombieEnabled)
常见异常Exec_Bad_Access问题解决办法:
在iOS开发中,经常遇到Exec_Bad_Access异常,导致程序奔溃问题,一般这个问题都是因为过早的release对象,然后又对该对象发送消息导致这个问题。可以通过在Xcode中设置NSZombieEnabled变量来获取一些详细信息
Xcode 4之后的做法是:
Xcode 可用 cmd+shift+< 进到这个窗口。
菜单里Product->EditScheme->Run->Environment Variables, 添加NSZombieEnabled,并设置其值为YES,
需要注意的问题:
NSZombieEnabled只能在调试的时候使用,千万不要忘记在产品发布的时候去掉,因为NSZombieEnabled不会真正去释放dealloc对象的内存
2、重写object的respondsToSelector方法
在iphone开发的时候EXC_BAD_ACCESS这个bug时不容易找到原因的。
首先说一下EXC_BAD_ACCESS 这个错误,可以这么说,90%的错误来源在于对一个已经释放的对象进行release操作,或者操作一个在循环代码中被修改的序列中的对象。虽然使用NSZombieEnabled变量可以帮助你找到问题所在,但有的时候,即使通过设置NSZombieEnabled变量,还是不能定位到问题所在,这个时候,你可以试试重写object的respondsToSelector方法,显示出现EXEC_BAD_ACCESS前访问的最后一个object,下面是具体的步骤:
<code class="hljs vala has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#ifdef _FOR_DEBUG_ </span>
-(BOOL) respondsToSelector:(SEL)aSelector {
printf(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"SELECTOR: %s\n"</span>, [NSStringFromSelector(aSelector) UTF8String]);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> [super respondsToSelector:aSelector];
}
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#endif </span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
使用方法:
需要在每个object的.m或者.mm文件中加入上面代码(应该可以使用类属实现),并且在other c flags中加入-D FOR_DEBUG(记住请只在Debug Configuration下加入此标记)。这样当程序崩溃时,XCode的console上就会准确地记录了最后运行的object的方法。
3、让XCode反馈足够多的信息
在Edit–>Scheme里面 找到Arguments ,在Environment Variables这里添加
把下面2个值设置成YES
NSAutoreleaseFreedObjectCheckEnabled
NSDebugEnabled
2. add
NSZombieEnabled
,set the value with YES
3. add
MallocStackLogging
, set the value with YES.
4. add
NSAutoreleaseFreedObjectCheckEnabled
, set the value with YES.
5. add
NSDebugEnabled
, set the value with YES.
这种方法非常好用,建议在建立一个工程的时候,加入此设置
使用场景:
主要为了解决EXC_BAD_ACCESS问题,MallocStackLogging用来启用malloc记录(使用方式 malloc_history ${App_PID} ${Object_instance_addr})。
4、设置全局异常断点
在程序抛出异常时候,往往需要定位到异常
键入快捷键 cmd + 6 进入断点窗口,点击左下角的"+"按钮,选择弹出框的“Add Exception BreakPoint”项,如下图所示:
然后使用默认设置,点击"done"按钮,设置全局异常断点就完成了
5、LLDB调试器
实用LLDB命令
“po”命令是“print object”(打印对象)的简写。“$eax”是cup的一个寄存器。在一个异常的情况下,这个寄存器将会包含一个异常对象的指针。注意:$eax只会在模拟器里面工作,假如你在设备上调试,你将需要使用”$r0″寄存器。
命令名 用法 说明
|
expr |
expr 表达式 |
可以在调试时动态执行指定表达式,并将结果打印出来,很有用的命令。 |
po |
po 表达式 |
与expr类似,打印对象,会调用对象description方法。是print-object的简写 |
print |
print (type) 表达式 |
也是打印命令,需要指定类型。 |
bt |