做你喜欢做的事情,任何时候都不会太迟

0%

LLDB知多少?

每一位 iOS 和 macOS 开发者都是幸运的,因为苹果的 Xcode 和 LLDB 调试工具,这是每一位开发者应该使用的调试神器,可以帮助我们更快地解决问题。接下来主要讲解 Xcode 的 断点调试LLDB 调试器 以及 视图结构调试(UI Hierarchy)的使用技巧,这些技巧将大幅减少调试中重新编译的次数,减少你的等待时间。这些技巧使用起来非常简单,而且在开发场景非常实用,大家都有必要掌握这些技巧。

WWDC 2018 Session 412 : Advanced Debugging with Xcode and LLDB

1、LLDB命令格式如下:
1
<command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument [argument...]]

LLDB命令的各部分由空格分割,如果参数中包含空格,则需要使用双引号括起参数,如果参数中包含双引号或者反斜杠,则需要使用反斜杠进行转义。

1
breakpoint set -n "-[ViewController-touchesBegan:withEvent:]"
2、LLDB命令有非常多的功能,完全背下来不太容易,也没必要。开发者可以使用 help 命令查看相关命令的用法,甚至可以查看 help 命令的用法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apropos           -- 列出与单词或主题相关的调试器命令
breakpoint -- 在断点上操作的命令 (详情使用'help b'查看)
bugreport -- 用于创建指定域的错误报告
command -- 用于管理自定义LLDB命令的命令
disassemble -- 拆分当前目标中的特定说明。 默认为当前线程和堆栈帧的当前函数
expression -- 求当前线程上的表达式的值。 以LLDB默认格式显示返回的值
frame -- 用于选择和检查当前线程的堆栈帧的命令
gdb-remote -- 通过远程GDB服务器连接到进程。 如果未指定主机,则假定为localhost
gui -- 切换到基于curses的GUI模式
help -- 显示所有调试器命令的列表,或提供指定命令的详细信息
kdp-remote -- 通过远程KDP服务器连接到进程。 如果没有指定UDP端口,则假定端口41139
language -- 指定源语言
log -- 控制LLDB内部日志记录的命令
memory -- 用于在当前目标进程的内存上操作的命令
platform -- 用于管理和创建平台的命令
plugin -- 用于管理LLDB插件的命令
process -- 用于与当前平台上的进程交互的命令
quit -- 退出LLDB调试器
register -- 命令访问当前线程和堆栈帧的寄存器
script -- 使用提供的代码调用脚本解释器并显示任何结果。 如果没有提供代码,启动交互式解释器。
settings -- 用于管理LLDB设置的命令
source -- 检查当前目标进程的调试信息所描述的源代码的命令
target -- 用于在调试器目标上操作的命令
thread -- 用于在当前进程中的一个或多个线程上操作的命令
type -- 在类型系统上操作的命令
version -- 显示LLDB调试器版本
watchpoint -- 在观察点上操作的命令
  • 执行命令 expression 是最基础的命令,简写为 expr 或者 e

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    expression self.nickNameLabel.text = @"";
    // 刷新UI
    expression [CATransaction flush]
    expression model.vip = NO;
    c

    e id $myView = (id)0x7fafa4977bf0
    e (void)[$myView setBackgroundColor:[UIColor blueColor]]
    e (void)[CATransaction flush]

    e ((UILabel *)0x100f2c100).backgroundColor = [UIColor redColor]
  • 打印命令 print 是最常用的命令,简写为 pri 或者 p ,通过help print会发现print其实是expression --命令的简写:'print' is an abbreviation for 'expression --',其中--标识选项的结束和参数的开始。 同样常用的 expression 简写命令还有 pocall。其中 po 表示 print object ,用来打印对象,call 用来调用某个方法。

    可以按照print/的语法为print命令指定打印格式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    p/x  //!< 以十六进制打印整数
    p/d //!< 以带符号的十进制打印整数
    p/u //!< 以无符号的十进制打印整数
    p/o //!< 以八进制打印整数
    p/t //!< 以二进制打印整数
    p/a //!< 以十六进制打印地址
    p/c //!< 打印字符常量
    p/f //!< 打印浮点数
    p/s //!< 打印字符串
    p/r //!< 格式化打印
  • thread是线程相关的命令,它可以接受不同的可选参数,以实现丰富的功能。

    1
    2
    3
    4
    thread list
    thread backtrace
    thread return
    thread jump --by 2
    3、LLDB 调试增强插件 Chisel 安装
1
brew install chisel
  • 我们在根目录下的 .lldbinit 文件中添加如下代码

    1
    2
    3
    # ~/.lldbinit
    ...
    command script import /usr/local/opt/chisel/libexec/fblldb.py
  • pviews 这个命令可以打印一个view的层级,如:

    1
    pviews self.view
  • pvc 查看控制器层次

  • pinternals 打印出任意控件的内部详情

    1
    pinternals self
  • visualize 使用 mac 的预览打开一个视图

    1
    visualize 0x7f9bcf0355f0
  • show & hide 这两个命令用来显示和隐藏一个指定的 UIView

    1
    show self.view
  • caflush 刷新UI界面。一般我们用 LLDB 语法改变UI,UI 并不会立即更新,我们需要使用 caflush 刷新界面

  • pclass 可以打印一个对象的继承关系 pclass self

  • pdocspath 打印 App 的 Documents 路径

  • pjson 打印一个字典或者数组的 json 样式