您的位置:首页 > 移动开发 > IOS开发

认识Xcode的调试器:LLDB调试技术

2017-03-20 11:16 501 查看


引言

调试技术无关乎任何功能性开发技术,但又对开发的效率影响至深。

那么何为调试呢,比如我们用 print 函数在指定位置进行输出,来定位某些节点的变量内的取值:

let result = parseJSON("[1,2,3]");
print(result);
result = parseJSON("error");
print(result);


相信我们大家看到类似这样的代码都不会陌生,估计为开发者朋友都会或多或少的用这样的方式对程序进行调试。

这种方式有它的方便之处,就是我们不需要太多思考,需要跟踪某些地方的时候,直接输出就可以得到调试信息了。但这样做也有它的弊端,就是我们每次这样调试,都要反复的编译,运行,然后写进新的 print 语句,再继续编译,运行。反复的编译,运行会比较消耗时间。并且我们再调试完之后,很容易会忘记将调试语句删除,导致很多输出语句遗留再代码中,随着项目的长期进展后,这样会对项目后期的调试造成很多干扰。

而且,当我们想再次调试这段区域的时候,我们不得不再次写上这些输出语句。而有时对于稍微复杂一些的调试场景,print 输出这样的方式,往往还不能太好的应对。

那么有什么办法能解决这些麻烦呢,那就是调试技术,调试器几乎在大多数现代的开发环境中都会有,所以,iOS 开发也不例外,最新版的Xcode 环境为我们提供的对应调试工具就是 LLDB。

什么是GDB和LLDB

我们在开发iOS程序的时候常常会用到调试跟踪,如何正确的使用调试器来debug十分重要。xcode里有内置的Debugger,老版使用的是GDB,xcode自4.3之后默认使用的就是LLDB了。

GDB:
UNIX及UNIX-like下的调试工具。

LLDB:
LLDB是个开源的内置于XCode的具有REPL(read-eval-print-loop)特征的Debugger,其可以安装C++或者Python插件。

所以他们两个都是调试用的Debugger,只是LLDB是比较高级的版本,或者在调试开发iOS应用时比较好用,不然人家苹果为什么换成了LLDB了呢!

lldb与gdb命令名的对照表:http://lldb.llvm.org/lldb-gdb.html


LLDB的使用

在程序里你需要的地方设置断点。当断点断住的时候你就能看到我们进入LLDB调试器了。



这时我们就可以使用一些LLDB命令来进行一些调试了。

调试快捷键:(Xcode常用快捷键)

command+shift+Y 打开调试窗口
command+Y 调试运行程序
command+option+P 继续
command+shift+O 跳过
command+shift+I 进入
command+shift+T 跳出

help命令

help会列出所有命令列表,用户加载的插件一般来说列在最后。

执行help 可以打印指定command的帮助信息。

比如:help print会打印内建命令print的使用帮助。





print命令

print命令的简化方式有prin、pri、 p,唯独pr不能用来作为检查,因为会和process混淆,幸运的是p被lldb实现为特指print。

实际上你会发现,lldb对于命令的简称,是头部匹配方式,只要不混淆,你可以随意简称某个命令。

例如:



最前面的(int)是类型。$是命令结果的引用名,使用$0可以进行print $0 + 7这样打印出17。

输出view 下 subview 的数量:
由于 subview 的数量是一个 int 类型的值,所以我们使用命令p:
(lldb)p (int)[[[self view] subviews] count]

直接调用方法改变背景颜色之类:
其实使用p,po,call都可以调用方法,只是p和po都是用于输出的有返回值的。call一般只在不需要显示输出,或是方法无返回值时使用。
(lldb)p [self.view setBackgroundColor:[UIColor redColor]]
(lldb)p (void)[CATransaction flush]

上述的p一般使用call比较好,因为方法是没有返回值的。


po命令

命令po跟p很像。p输出的是基本类型,po输出的Objective-C对象。调试器会输出这个 object 的 description。

例如:



expression命令

expression的简写就是e。可以用expression来声明新的变量,也可以改变已有变量的值。我们看到e声明的都是\$开头的变量。我们在使用时也需要加上\$符号。

例如:

创建新的变量



注意:如果上面这里输入以下命令,会发生错误。说明lldb无法判定某一步的计算结果是什么数据类型,这时需要强制类型转换来告诉lldb。
(lldb) p [[$array objectAtIndex:0] characterAtIndex:0]
error: no known method '-characterAtIndex:'; cast the message send to the method's return type
error: 1 errors parsing expression

(lldb) p (char)[[$array objectAtIndex:0] characterAtIndex:0]
'o'

修改已有变量




image命令

image 命令可用于寻址,有多个组合命令。比较实用的用法是用于寻找栈地址对应的代码位置。 下面我写了一段代码
NSArray *arr=[[NSArray alloc] initWithObjects:@"1",@"2", nil];
NSLog(@"%@",arr[2]);

这段代码有明显的错误,程序运行这段代码后会抛出下面的异常:



现在,我们怀疑出错的地址是0x0000000100004af8(可以根据执行文件名判断,或者最小的栈地址)。为了进一步精确定位,我们可以输入以下的命令:

(lldb)image lookup --address 0x0000000100004af8
(lldb)im loo -a 0x0000000100004af8

命令执行后返回:

Address: ControlStyleDemo[0x0000000100004af8] (ControlStyleDemo.__TEXT.__text + 13288)
Summary: ControlStyl


我们可以看到,出错的位置是RootViewController.m的第53行。


设置断点触发条件



参考

LLDB使用篇

LLDB调试命令初探

深入了解GDB和LLDB

iOS 开发者旅途中的指南针 - LLDB 调试技术
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息