一.设置和查看断点
断点可以分为以下3种类型。
1. 文件行断点设置
添加断点->右键选择Edit Breakpoint
Condition:指的是条件表达式,该项允许我们对断点生效设置条件,表示当满足某一特定条件的前提下,该断点才生效。(该条件的录入,不能够识别预处理的宏定义,也不能识别断点作用域之外的变量和方法)。eg:i == 1 ; (i == 1 || i == 2)
Ignore:忽略次数。它指定了在断点生效,应用暂停之前,代码忽略断点的次数。你如果希望应用运行一段时间后断点才生效,那么就可以使用这个选项。比如说在调试某一循环体的时候。eg:Ignore 2 == 前两次执行此处的代码不会触发该断点,从第三次开始触发该断点。如果数字为n,则从第n次开始触发该断点。
Action:动作。它表示当断点生效时,Xcode作出反应后的行为动作。点击右边的Add Action选项会弹出如图
图中所示红色方框中的选项,可以让你指定那一种动作。默认的是Debugger Command。还有以下几种动作供选择,下面逐一介绍。
它是苹果提供的一种脚本语言,用来执行一些预先指定的行为。选中该选项,将会出现如图所示的AppleScript语言的输入框。
大家可能看到了,我在输入框中输入了本门至高无上的心法秘诀,它的意思是弹出一个显示“Hello World!”的对话框。点击Compile按钮后,如果没有错误,会显示成功信息。而点击Test按钮,会测试运行效果,如下图
(2).Capture GPU Frame
这个功能用于当断点生效时,捕获GPU当前所绘制的帧。该功能是辅助图形调试的。
(3).Debugger Command
默认的选项,可以让断点执行LLDB调试命令。
po _imageArray 打印该断点上面用到的数组内容
(4).Log Message
使用Log命令可以生成消息队列,将相关的消息输出到控制台上,还有一个Speak Message选项,可以播报消息。
(5).Shell Command
该动作接收一个命令文件和参数列表。如下图所示
命令文件必须是一个可执行的二进制程序或者脚本。可以复制粘贴输入路径,也可以点击Choose按钮选择具体文件。
参数通过空格表示分割,也可以在两个@字符之间包含LLDB表达式。
一般情况下,Xcode会异步执行Shell Command,也就是说,Shell Command 和调试器将会同步执行。如果希望调试器在Shell Command命令完成后运行,则可以勾选下面的Wait until done选项。
(6).Sound
动作会在断点被触发时,弹出声音提示。
Options: 在执行完事件之后自动继续执行。选中该选项之后,程序不会止步于该断点,遇到该断点也会继续执行,但是会响应action中的调试信息。
设置符号断点与设置文件行断点不同,需要点击导航面板中的按钮打开断点导航面板,如图
15-10
所示。
在断点导航面板中,可以看到所有的断点。
其中有两项
——Add Symbolic Breakpoint
和
Add Exception Breakpoint
,前者可以创建符号断点,后者可以创建异常断点。这里我们选择
Add Symbolic Breakpoint
菜单项,此时可以弹出创建符号断点对话框,如图
Symbol:后面可以是
1. 方法名称:会对所有具有此方法名称的类方法生效。例如 initWithFrame: 。
2. 特定类的方法:OC类和C++类都适用,例如 ,[UIView initWithFrame:]或者 Shap::draw()。
3. 函数名称。例如普通C函数。
Module:是模组的意思,用来限制满足符号的方法,编译器将只会在断点满足这个模组的符号的时候才回暂停
其余的选项同上。
3. 异常断点设置
Exception选项可以让你选择响应Objective-C对象抛出的异常,也可以选择响应C++对象抛出的异常。
Break则是选择断点所接收的异常,是接收“Throw”语句抛出的异常还是Catch语句的。
3.OpenGL ES错误断点(OpenGl ES Error Breakpoint)
这个断点的作用和异常断点类似,只不过这个断点只有在openGL ES错误发生的时候才会触发。
4.测试失败断点 Test Failure Breakpoint
仅在测试断点失败的时候才会执行,这个时候,应用将会暂停在引发测试失败的代码处,而不是停止在测试代码处。
二、调试工具栏
模拟位置按钮左边的为图层查看按钮,点击可以查看界面的各个图层
变量查看窗口
Auto。查看经常使用的变量。
Local Variables。查看本地变量。
Variables, Registers, Globals and Statics。查看全部变量,包括寄存器和全局变量等,如图
15-25
所示,
其中图标
A
是自动变量、
S
是静态变量、
R
是寄存器、
L
是本地变量。
Print Description of “i” 打印变量信息
Edit Value… 编辑变量的值
三、
日志与断言输出
1.使用NSLog函数
2. 使用NSAssert宏
NSLog
函数是无条件输出,即程序运行到该语句,就会输出结果。如果想有条件输出结果,可以使用
NSAssert
宏。注意,
NSAssert
并不是函数,它的定义如下:
#define NSAssert(condition, desc, ...)
其中第一个参数
condition
是布尔表达式,第二个参数
desc
是描述信息,参数后面的
...
是格式化
desc
描述信息
的。如果
condition
为
NO
,则输出
desc
描述信息,并抛出异常
NSInternalInconsistencyException
;如果
condition
为
YES
,则不输出信息。
2. 移除项目中的打印信息
(1)移除NSAssert
NS_BLOCK_ASSERTIONS
是
Foundation
框架中定义好的预处理宏,如果在编译环境中设置
NS_BLOCK_ASSERTIONS
,
在编译的时候
NSAssert
宏将被移
(2) 移除NSLog
扩展:
1.自己在pch文件中预定义如下宏
#ifdef MY_MACRO
#define NAME @
"
测试版本
"
#else
#define NAME @
"
上线版本
"
#endif
2.
设置preprocessor Macros—>Debug(添加
MY_MACRO=1)
3.在项目中使用NAME宏
如果项目Scheme编译模式为Debug 输出:name = 测试版本
如果项目Scheme编译模式为release 输出:name = 上线版本
四、LLDB调试工具
p
和
po
就是调试工具的
命令,调试工具的编译器相对独立于
Xcode
。我们进行
Objective-C
程序开发时,用过
3
种编译器
——GCC
、
LLVM
GCC
和
Apple LLVM
,其中
GCC
是比较古老的编译器,现在我们主要使用
LLVM GCC
和
Apple LLVM
。
GCC
的调试
工具是
GDB
,是
GCC Debug
工具的缩写,
LLVM GCC
和
Apple LLVM
的调试工具是
LLDB
(或
lldb
)。
进入
LLDB
调试工
具的一种方式是从终端进入,另外一种是从
Xcode
进入。
Xcode
工具我们比较熟悉,这里主要介绍这种方式。具体
做法很简单,就是在程序中设置断点,当程序挂起时,在输出窗口中选择
Debugger Output
,这时输出窗口有
(lldb)
命令提示符,这就进入了
LLDB
调试工具了。
常用命令:po
五、异常堆栈报告分析
[exception reason] 异常产生的原因
[exception callStackSymbols] 符号化打印
查看设备的崩溃日志
Window—>Devices—>View Device Logs
点击Re-Symbolicate Log 符号化日志信息
红色标注部分指出崩溃代码在ViewController0.m的第60行代码
六、符号化设备的崩溃日志
1.手动
符号化设备的崩溃日志
我们在ios开发中会碰到的很多crash问题,如果Debug调试模式的话,我们可以往往很容易的根据log的输出定位到导致crash的原因,但对于已经上线的应用,或者是release环境包导致的crash,我们就需要一些特殊的手段来通过crash log进行分析定位了。
通过参考网上的一些资料,总结了一下,下面介绍一下通过dSYM文件以及crash log分析定位的方法。
1.导出crash log
通过Xcode的Organizer查看某台iphone设备的DeviceLog,选择需要的crash log,导出XXX.crash文件。
2.找到对应的app文件
找到当前iphone设备上安装的ipa文件,更改文件后缀名为zip,解压后得到Payload文件夹,你需要的app文件就在其中了。
3.找到对应build版本的dSYM文件
dSYM文件是iOS编译后保存16进制函数地址映射信息的文件,每次应用程序build后,都会生成对应的xxx.app, xxx.app.dSYM文件。
4.确定dSYM、app以及crash文件的关系
首先将
dSYM、app以及crash放入同一个文件夹中,通过终端进入该文件夹。
每一个xx.app, xxx.app.dSYM文件都拥有相应的uuid,crash文件也有uuid,只有三者uuid一至才表明之三者可以解析出正确的日志文件。
查看xx.app文件的uuid的方法,在terminal中输入命令:
dwarfdump --uuid xxx.app/xxx (xxx工程名)
查看xx.app.dSYM文件的uuid的方法,在terminal中输入命令:
dwarfdump --uuid xxx.app.dSYM (xxx工程名)
而.crash的uuid位于,crash日志中的Binary Images:中的第一行尖括号内。如:
armv7 <8bdeaf1a0b233ac199728c2a0ebb4165>
5.通过symbolicatecrash分析crash文件
Xcode有自带的symbolicatecrash工具,可以通过dSYM文件将crash文件中的16进制地址转换成可读的函数地址。该文件是隐藏文件,可以通过如下命令查找并拷贝到系统目录下,并建立快捷方式。
1)打开终端,进入到symbolicatecrash工具所在的文件夹目录
第一步:找到
symbolicatecrash工具所在的文件夹目录
find /Applications/Xcode.app -name symbolicatecrash(速度快)
或者
find /Applications/Xcode.app -name symbolicatecrash -type f
运行结果
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash
第二步:进入该目录
cd
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash
2)查找确认是否存在symbolicatecrash(可省略)
ls -al | grep symbolicatecrash
bogon:Resources bang$ ls -al | grep symbolicatecrash
-rwxr-xr-x 1 root wheel 37893 2 26 10:22 symbolicatecrash
3)将symbolicatecrash工具拷贝到
dSYM、app以及crash所在的文件夹
bogon:Crash bang$ cp symbolicatecrash /Users/bang/Desktop/Crash
4)执行如下命令,即可正确解析crash文件
./symbolicatecrash xxx.crash xxx.app.dSYM > test.txt
./symbolicatecrash DemoModel.crash CA3ACCD1-F63D-3A37-9773-82B155C02DA6.dSYM >crash2.txt
5)打开crash2.txt就可以看到符号化的崩溃日志了
2.通过友盟符号化设备的崩溃日志
如果出现bug的构建版本是在自己的电脑上打包的,那么直接打开终端输入黑色部分的代码就能定位到崩溃的代码位置;
如果出现bug的构建版本不是在自己电脑上打包的,那么需要找到对应的构建版本拷贝到自己项目中构建版本的目录中