您的位置:首页 > 其它

Xcode 报错 大体解决方法

2015-10-29 20:40 316 查看

1、使用僵尸变量(NSZombieEnabled)

具体使用及设置,可参考我的另一篇博文:/article/1564302.html

常见异常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″寄存器。

命令名 用法 说明
exprexpr 表达式可以在调试时动态执行指定表达式,并将结果打印出来,很有用的命令。
popo 表达式与expr类似,打印对象,会调用对象description方法。是print-object的简写
printprint (type) 表达式也是打印命令,需要指定类型。
btbt [all]debug 模式(必须在这个模式下),在程序
crash 之后,在控制台输入 bt,就可以显示 crash 堆栈

打印调用堆栈,是thread backtrace的简写,加all可打印所有thread的堆栈。
br lbr l是breakpoint list的简写
process continue lprocess continue简写:c
thread step-in lthread step-in l简写:s
thread step-inst lthread step-inst l简写:si
thread step-over lthread step-over l简写:n
thread step-over-inst lthread step-over-inst l简写:ni
thread step-out lthread step-out l简写:f
thread listthread list简写:th l


内存泄漏隐患提示:
Potential Leak of an object allocated on line ……数据赋值隐患提示:The
left operand of …… is a garbage value;对象引用隐患提示
Reference-Counted object is used after it is released;


6.运行时设置断点

在XCode中需要观察的变量所在的代码处添加断点,可以让程序运行到这里暂停。这时鼠标悬停在变量名处,XCode会显示出该变量的信息。

断点的类型分为异常断点(Exception Breakpoint)和符号断点(Symbolic Breakpoint)等,在XCode断点浏览器(Breakpoints Navigator)的左下方可以添加这些断点。



符号断点中的符号可以指方法名称或函数名称。符号断点可以中断某个函数的调用。用户还可以添加执行断点的条件。



异常断点可以使程序在每次发生异常时,都会被中断。一般用来捕获未知异常。




技巧一:运行时修改变量的值

你以前怎么验证是不是某个变量的值导致整段程序不能正常工作?修改代码中的变量的值,然后cmd+r重新启动app?现在你不需要这么做了,只需要设置一个断点,当程序在这进入调试模式后,使用expr命令即可在运行时修改变量的值。

假如有一个loginWithUsername:方法,需要两个参数:username,password。

首先设置好断点,如下图所示:





运行app,进入断点模式后,在(lldb)后输入

?
控制台会返回以下信息

?
现在跳出断点,执行断点之后的两条输出语句,控制台会有以下输出

?
我们在运行时修改了变量的值,事情还可以变的更简单一些,我们可以编辑断点,让它自动填充需要的修改的变量的值,并且可以选择在此断点处不进入断点模式,仅仅修改指定变量的值,然后自动执行后续代码。

右击断点选择“Edit Breakpoint...”(或者按住cmd+option,单击断点),然后如下图所示设置断点





注意选中了最后一行(“Automatically continue after evaluating”)的选择框,这就保证运行到这个断点的时,填充变量的值,然后继续运行,并不在此处断点进入调试模式。

运行app,你会得到和上述手动设置变量的值一样的输出。

接下来单击断点,使其处于禁用状态,现在箭头的颜色应该是浅蓝色的,重新运行app,你会发现username和password的值没有在运行时被改变了。


技巧二:设置断点触发条件

断点的另外一个重要作用,是可以设置触发断点生效的条件,这样我们就可以在运行时针对特定的数据进行分析,观察app是否运行在正确的轨道上。如下图:





上述截图可以看到如下语句

?
通过这行语句,我们告诉编译器:当item中ID等于93306时,此断点生效,进入断点调试模式。


技巧三:格式化输出数据

如果你厌倦了代码里无穷无尽的NSLog,幸运的是我们可以在编辑断点使其输出格式化字符串就像平常编码时一样。不过有一点需要注意,平常编码时可能会使用NSString‘s stringWithFormat:输出格式化字符串,不过这个方法貌似在断点中木有效果,你需要使用alloc/init形式的方法,如下:

?




运行app,就能在控制台看到想要的输出啦!


7. 打印到控制台

控制台位于XCode的底端,用于打印程序运行过程中的输出信息。在代码中调用NSLog函数,可以打印变量值到控制台中显示出来。
<code class="hljs http 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-attribute" style="box-sizing: border-box;">NSLog(@"obj</span>: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">%@", obj); </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></ul>


需要特别注意的是,尽管NSLog可圈可点,但在实际应用中要防备其可能会引起安全问题,因为任何由NSLog输出的内容都会成为应用程序成品代码的一部分,也就是说会被任何接触到应用的人看到。只要把设备接入信息管理工具,每个人都能查看控制台信息并查询每一条日志记录。这可能会引发一系列严重后果,例如向控制台输出机密逻辑算法或者用户密码等信息。

我们可以使用宏来解决调用NSLog方法可能导致的安全问题,只在调试版本中调用NSLog。可以采用全局可访问的头文件,把所有日志记录都灌进去,而且不用担心它们会出现在成品代码当中。
<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 DEBUG  </span>

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define DMLog(...) NSLog(@"%s %@", __PRETTY_FUNCTION__, [NSString stringWithFormat:__VA_ARGS__])</span>

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#else</span>

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define DMLog(...) do { } while (0) </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><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>


现在如果我们使用DMLog(这个名称可以随便起),它将只向调试版本输出结果,任何成品代码都不会受到影响。PRETTY_FUNCTION也帮上了大忙,它会根据日志信息来源为函数命名。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: