iOS 宝典

UI 调试利器 Chisel 的使用

2017-10-04  本文已影响176人  貘鸣

参考文章1: 调试器的妙用

LLDB调试器和GDB调试器命令映射表

1 什么是 Chisel

Chisel 是一个 LLDB 命令集, 用于辅助 iOS 程序的调试. 它的 Github 主页在这里.

要了解 Chisel, 首先需要了解什么是 LLDB. 如果已经了解过相关知识, 请直接跳过 LLDB 相关内容.

2 LLDB 简介

众所周知, 一个典型的bug修复周期包括: 修改代码—>编译—>运行, 然后祈祷结果是对的. 其实还有更快和更简单的办法, 就是利用 LLDB, 但千万不要只把它当做值的观察器来使用!

LLDB 是一个开源调试器, 其特点是: 实现了一个"读取-求值-输出""循环, 并且拥有众多的 C++ 和 Python 插件, 并且已经被集成到了 Xcode 中.

LLDB 有众多的插件, 而 Chisel 就是它的一个利用 Python 语言写的插件集, 下面先来看看 LLDB 的基本使用.

3 LLDB 的基本使用

首先来看如下的代码, 当触发断点后, LLDB 命令行输入会出现在界面的左下角:

设置断点

下面就来看看一些 LLDB 的基本命令的使用.

3.1 help 命令

最简单的命令是 help, 它会列出 LLDB 的帮助信息, 如果忘记某个命令的用法, 则可以使用 help <command> 来打印该命令的详细信息, 比如 help print 或者 help thread. 当然也可以这样用 help help 😝.

3.2 print 命令

有时希望打印出某个变量的值, 则可以使用 print 命令:

使用 print 命令

由于 LLDB 会自动进行命令前缀匹配, 则实际上该命令还可以这样写: prin, prip. 但不能使用 pr, 因为它和 process 命令冲突.(LLDB 中规定 p 是对应 print, 所以请放心使用)

另外结果被自动放入了一个 $0 变量中, 所以接下来还可以使用该变量. 比如 print $0 + 9, 则会打印 108.

在 LLDB 中, 任何以 $ 符号开头的变量都可以在接下来的命令中进行使用.

3.3 expression 命令

调试的时候, 有时候想直接为某个变量赋值, 然后观察后续代码的行为. 此时就可以用 expression 命令来改变某个变量的值. 注意, 这里改变的并非 LLDB 中变量的值, 而是运行程序中变量的值!

下面就来使用 pe (分别是 printexpression 的缩写)做些事情.

3.4 print 命令详解

来看这条 LLDB 语句: p count = 18. 这条语句会直接改变 count 的值并打印出来. 如果使用 help print, 就会发现如下输出:

'print' is an abbreviation for 'expression --'.

其中的"两道杠"是用来分隔标志位和表达式.

假设实际使用时输入 e -h +17, 此时无法分辨到底 -h 指的是标志位, 还是说变量 h 的相反数. 所以需要"两道杠"分隔符, 这样就很容易分辨了:

e -h -- +17 中 -h 指的是标志位
e -- -h +17 中 -h 指的是h的相反数

所以 printexpression 无标志位时候的缩写.

3.5 打印程序中的对象

我们调试的时候想打印一个对象, 但是直接执行 p object 的话, 结果往往是😂:

(NSString *) $7 = 0x0000000104da4040 @"red balloons"

甚至是😂:

(lldb) p @[ @"foo", @"bar" ]

(NSArray *) $8 = 0x00007fdb9b71b3e0 @"2 objects"

实际上我们只想打印该对象的 description 方法所输出的内容, 这时可以使用 -O 标志:

(lldb) e -O -- $8
<__NSArrayI 0x7fdb9b71b3e0>(
foo,
bar
)

清爽了好多. 该命令的缩写是 po (print object), 使用 po 的效果和上面一模一样:

(lldb) po $8
<__NSArrayI 0x7fdb9b71b3e0>(
foo,
bar
)

3.6 按指定形式打印

使用 print 打印时数字, 默认是10进制:

(lldb) p 16
16

可以使用 print/<fmt> 指定打印的形式, 比如 x 表示十六进制:

(lldb) p/x 16
0x10

使用 t 表示二进制:

(lldb) p/t 16
0b00000000000000000000000000010000
(lldb) p/t (char)16
0b00010000

另外 p/c 表示字符(character), p/s 表示字符串(string, 即以 \0 结尾的 char*).

这里是所有可选的输出形式参数列表.

3.7 变量

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 无法区分变量类型, 所以需要给它一些提示:

(lldb) p (char)[[$array objectAtIndex:$a] characterAtIndex:0]
'M'
(lldb) p/d (char)[[$array objectAtIndex:$a] characterAtIndex:0]
77

3.8 流程控制

可以使用 LLDB 命令来控制调试流程, 调试过程中的流程控制命令有如下四个:

讲了这么多关于 LLDB 的内容, 下面就来看如何安装和使用 Chisel.

4 安装 Chisel

可以使用 HomeBrew 来安装 Chisel, 根据命令行提示完成安装即可:

brew update
brew install chisel

也可以直接下载 Chisel, 然后添加 ~/.lldbinit 文件, 内容如下:

# ~/.lldbinit
...
command script import /path/to/fblldb.py

注意, 写这个文档的时候, chisel是1.5.0版本, 用 homebrew 安装完成后, 有可能 .lldbinit 文件并没有被创建, 导致在 Xcode 中无法使用 chisel. 故需要在用户根目录手动创建 .lldbinit 文件, 并添加文件内容:

command script import /usr/local/opt/chisel/libexec/fblldb.py

这里该 fblldb.py 文件的位置可能有所不同, 需要根据情况修改.(该文件路径在安装 chisel 的时候会有提示)

安装完成后, 再次启动 Xcode 时, 就可以在 LLDB 中使用 Chisel 中的所有命令了.

5 如何使用 Chisel

由于 Chisel 是一个 LLDB 命令集插件, 故使用时直接调用其提供的命令即可.

要查询所有命令, 可以在 LLDB 中执行help, 或查看 Chisel 官方命令列表: 完整命令列表.

(lldb) help
The following is a list of built-in, permanent debugger commands:
...

The following is a list of your current user-defined commands:
...

下面是一些常用命令:

命令 含义 iOS OS X
pviews Print the recursive view description for the key window. Yes Yes
pvc Print the recursive view controller description for the key window. Yes No
visualize Open a UIImage, CGImageRef, UIView, CALayer, NSData (of an image), UIColor, CIColor, or CGColorRef in Preview.app on your Mac. Yes No
fv Find a view in the hierarchy whose class name matches the provided regex. Yes No
fvc Find a view controller in the hierarchy whose class name matches the provided regex. Yes No
show/hide Show or hide the given view or layer. You don't even have to continue the process to see the changes! Yes Yes
mask/unmask Overlay a view or layer with a transparent rectangle to visualize where it is. Yes No
border/unborder Add a border to a view or layer to visualize where it is. Yes Yes
caflush Flush the render server (equivalent to a "repaint" if no animations are in-flight). Yes Yes
bmessage Set a symbolic breakpoint on the method of a class or the method of an instance without worrying which class in the hierarchy actually implements the method. Yes Yes
wivar Set a watchpoint on an instance variable of an object. Yes Yes
presponder Print the responder chain starting from the given object. Yes Yes
... ... and many more!

Chisel 特别在界面调试上有很大用途. 下面仅挑常用的说, 详细文档请移步这里.

上一篇下一篇

猜你喜欢

热点阅读