UI 调试利器 Chisel 的使用

参考文章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 命令来控制调试流程, 调试过程中的流程控制命令有如下四个:

  • 继续: c
  • 单步: n
  • 单步进入: s
  • 单步退出: finish

讲了这么多关于 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 特别在界面调试上有很大用途. 下面仅挑常用的说, 详细文档请移步这里.

  • show 和 hide:

    比如界面上有一个label, 变量名为 textLabel, 要显示它, 则使用:

    show textLabel
    

    要隐藏, 则使用:

    hide textLabel
    
  • alamborder 和 alamunborder:

    alamborder 可以将界面上存在歧义布局(ambiguous layout)的视图标注出来, 比如标注为红色边框, 边框线宽为2, 则使用(如果指定参数, 则:

    alamborder --color=red --width=2
    

    要取消, 则使用:

    alamunborder
    
  • border 和 unborder

    将一个视图用线框包裹起来:

     border xyzLabel
     unborder //隐藏
    

    执行这个命令, 它会使用默认配置: 即红色边框将该视图的矩形框标识出来. 当然也可以指定颜色线宽和其他参数.

  • dismiss

    将使用 present: 方法显示出来的 VC 取消显示:

     dismiss xxxViewController
    
  • flicker

    当看到一个视图变量, 但在代码中找很久都找不到它到底对应界面上什么东西的时候, 这个命令就可以出来帮忙了, 比如有一个 xyzLabel 变量, 你只知道它是个label 😂, 但如何找到它呢? 就使用如下方法, 这时 xyzLabel 会在界面上快速显隐两次, 这样就知道它在哪里了:

    flicker xyzLabel

  • mwarning

    模拟一个内存警告.

  • pactions

    打印某个 control 的所有 action 和 target:

      pactions xxxButton
    
  • pbcopy

    打印指定对象, 且将输出拷贝到剪贴板.

  • pbundlepath

    打印应用程序的 bundle 目录的地址.

  • pclass

    打印某目标对象的类型继承链:

     (lldb) pclass self
     HomeBoard_iPhone
        | BaseRootBoard_iPhone
        |    | BeeUIBoard
        |    |    | UIViewController
        |    |    |    | UIResponder
        |    |    |    |    | NSObject
    
  • pdata

    将某 NSData 中的内容以字符串的形式打印出来, 并且可以指定编码, 默认是 utf-8:

    pdata valueData
    
  • pdocspath

    打印本应用的 Documents 目录路径.

  • pinternals

    打印某对象的内部情况:

    (lldb) pinternals valueData
    (_NSInlineData) $705 = {
      NSData = {
        NSObject = {
          isa = _NSInlineData
        }
      }
      _length = 9
    }
    
  • pjson

    以 JSON 格式打印字典或数组的内容:

    (lldb) pjson @[1, 2, 3]
    [
      1,
      2,
      3
    ]
    
  • pmethods

    打印指定类或对象的所有类方法和对象方法.

  • pproperties

    打印某对象或类型的所有属性

  • vs

    在当前视图树中搜索指定的视图.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容

  • [转]浅谈LLDB调试器文章来源于:http://www.cocoachina.com/ios/20150126/...
    loveobjc阅读 2,487评论 2 6
  • 你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThi...
    paraneaeee阅读 1,186评论 0 7
  • 你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThi...
    木易林1阅读 954评论 0 4
  • 转载 与调试器共舞 - LLDB 的华尔兹: https://objccn.io/issue-19-2/ 推荐:i...
    F麦子阅读 3,331评论 0 10
  • 与调试器共舞 - LLDB 的华尔兹 nangege 2014/12/19 你是否曾经苦恼于理解你的代码,而去尝试...
    McDan阅读 881评论 0 0