lldb 是 Xcode 中集成的一个开源调试器,可以减少我们每次调试程序时需要重新启动程序并逐级进入到指定页面的时间。
要使用 lldb 除了在代码中加断点外,还可以在程序运行时点击控制台上方第三个指令(Pause program execution)使程序进入暂停状态。
查看 lldb 的具体命令,可以通过在控制台输入 help 后回车查看。
下面介绍一些常用的命令
Evaluate an expression on the current thread. Displays any returned value with LLDB's default formatting.
计算当前线程上的表达式。使用LLDB的默认格式显示任何返回值。
简写:p
,使用如图
可以看到
p
命令能打印出变量的值及其类型,其中1 表示第1个,以此类推,后续可以用 $+数字表示该结果,以执行其他命令。
expression
Evaluate an expression on the current thread. Displays any returned value with LLDB's default formatting.
计算当前线程上的表达式。使用LLDB的默认格式显示任何返回值。
如果要改变一个值,可使用 expression 命令,简写 p
,使用如下图
e
不仅可以改变控制器中的值,还可以改变程序中的值。注意
p
是 e
不带参数的简写。当使用
p
打印对象时,只会打印出指针地址,这时我们可以使用 po
(e
的另一种格式)来实现。p
命令还可以设置打印格式,打印格式语法 pring/<fmt> 或 p/<fmt>默认格式
// 十进制
(lldb) p 16
16
// 十六进制
(lldb) p/x 16
0x10
// 二进制(t 代表 two)
(lldb) po/t 16
0b00000000000000000000000000010000
(lldb) po/t (char)16
0b00010000
lldb 定义变量
使用 lldb 定义变量需要在变量前以 $ 开头,如下
(lldb) e int $a = 2
(lldb) p $a * 19
38
(lldb) e NSArray *$array = @[ @"Saturday", @"Sunday", @"Monday" ]
(lldb) p [$array count]
2
(lldb) po [[$array objectAtIndex:0] uppercaseString]
SATURDAY
(lldb) p [[$array objectAtIndex:$a] 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:$a] characterAtIndex:0]
'M'
(lldb) p/d (char)[[$array objectAtIndex:$a] characterAtIndex:0]
77
流程控制相关
在调试程序的时候控制台上方工具栏一部分如下图
从左只有,3-7分别为 continue \ step over \ step into \ step out
contine(c):取消程序的暂停,允许程序正常执行下去直到遇到下一个断点。
step over(next 或 n):黑盒方式执行下一行代码,如果所在行是一个方法调用,不会跳进这个方法,而是执行这个方法,然后继续。
step into(step 或 s):跳进一个方法调试,若当前行不是方法调用,作用和
n
相同。step out:如果不小心跳进一个方法,使用
step out
命令可以继续执行到下一个返回语句然后再次停止。
Thread Return
调试时,使用 thread return 可以控制程序流程。
thread return
有一个可选参数,在执行时它会把可选参数加载进返回寄存器里,然后立刻执行返回命令,跳出当前栈帧。这意味着方法剩余的部分不会被执行。(提前跳出方法)
这会给 ARC 的引用计数造成一些问题,或者会使方法内的清理部分失效。但是在方法的开头执行这个命令,是个非常好的隔离这个方法,伪造返回值的方式 。
管理断点
Xcode 左侧 Navigator 倒数第二个选项(看起来像一个断点)下,这是衣蛾可以快速管理所有断点的面板。
lldb 同样可以做这件事,breakpoint list
(br li
)命令可以查看当前项目下所有的断点及其位置。
breakpoint enable <breakpointID>
和breakpoint disable <breakpointID>
命令可以用来开启或关闭某个断点。
如下图
断点
断点相关的打算单独写个帖子,我使用 Xcode 的断点,感觉比 lldb 命令方便点。
更新 UI
使用 recursiveDescription
方法可以递归返回指定 view 的层次结构,如下图
注意:
recursiveDescription
方法是系统私有方法,需要手敲,不会有代码提示。根据上面的方法,我们可以通过某个 view 的地址获取该 view,然后在调试器中改变它的颜色或其他一些属性。
// 获取 view 的层次结果
po [self.view recursiveDescription]
<UIView: 0x7fcea74069a0; frame = (0 0; 428 926); autoresize = W+H; layer = <CALayer: 0x600001a38ec0>>
| <UILabel: 0x7fcea7407db0; frame = (100 100; 100 30); text = 'lldb调试器'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x60000393c140>>
| <UIButton: 0x7fcea9008740; frame = (100 150; 150 30); opaque = NO; layer = <CALayer: 0x600001a0aba0>>
| | <UIButtonLabel: 0x7fcea7616950; frame = (10.6667 4; 129 22); text = '这是一个button'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x600003932a80>>
// 获取 view 的指定子视图 label
(lldb) e id $label1 = (id)0x7fcea7407db0
// 设置 label 的背景色
(lldb) e (void)[$label1 setBackgroundColor:[UIColor yellowColor]]
// 设置 label text 属性
(lldb) e (void)[$label1 setText:@"在lldb调试器中更新 UI"]
// Continue program execution(点击控制台上方工具栏的过断点按钮)继续运行程序
(lldb) c
在 lldb 调试器中运行上面的一系列命令后可以看到界面确实发生了变化,如下图
这种情况是只有程序继续运行才能看到界面的变化,因为改变的内容必须发送到渲染服务中才会显示更新。
渲染服务实际上是一个另外的进程 (被称作
backboardd
)。这就是说即使我们正在调试的内容所在的进程被打断了,backboardd
也还是继续运行着的。这意味着你可以运行下面的命令,而不用继续运行程序:
(lldb) e (void)[CATransaction flush]
此时你仍然在调试器中,但是界面会实时更新。
页面跳转
我们可以使用 lldb 调试器在控制台通过命令实现 push 跳转
// 创建跳转目的地
(lldb) e id $vc = [[ViewController1 alloc] init]
(lldb) p self
(ViewController *) $1 = 0x00007fec5e808f60
// 执行跳转
(lldb) e (void)[self.navigationController pushViewController:$vc animated:YES]
// 将跳转过程渲染到界面显示
(lldb) e [CATransaction flush]
(lldb)
// 执行 pop
(lldb) e (void)[self.navigationController popViewControllerAnimated:YES]
// 渲染--但是不好用,需要点击继续运行结束调试或者输入命令 `c` 结束调试才能执行 pop。
(lldb) e [CATransaction flush]
// 测试中发现 present 跳转也需要输入命令 `c`(继续运行结束调试)才好用。
网友评论