1. 前言
如果问你最常使用哪个 LLDB 命令? 我相信大多数 iOS 开发者都会回答 po
。 你是否知道实际上可以使用纯 Swift 代码自定义自己的 LLDB 命令吗?
在本文中将会向你展示如何创建你自己的 LLDB 命令。以下是将要分享的内容:
- 添加你的第一个 LLDB 命令
- 添加带参数的 LLDB 命令
- 将复杂的 Swift 代码转换为 LLDB 命令
2. 添加您的第一个 LLDB 命令
2.1 了解 LLDB 命令结构
为了添加自定义 LLDB 命令,我们必须利用 command alias
LLDB 命令。它结构如下:
1 | command alias [command_name] expr -l Swift -O -- [swift_code] |
对命令进行详细分解:
command alias
:使用名称为 Swift 代码添加别名的 LLDB 命令[command_name]
: 自定义命令名称expr -l Swift -O --
: 要求 LLDB 调试器将后面的所有内容解释为 Swift 代码[swift_code]
:定义自定义命令逻辑的 Swift 代码
举例说明,如果我们要添加一个别名为 greet
的自定义命令,在控制台上打印结果为 “Hello World!” ,LLDB 命令如下:
1 | command alias greet expr -l Swift -O -- print("Hello World!") |
2.2 添加自定义命令
现在已经构造了别名为 greet
的命令,然后添加到 LLDB 调试器中。
将 greet
命令添加到 LLDB 调试器的最直接方法是在 Xcode 控制台中执行别名命令。
但是,这样做只会使 greet
命令在当前特定调试会话中可用。 也就是说,每当开始新的调试会话时,我们就需要重新键入相同的别名命令。
为了避免这种情况发生,我们可以利用位于主目录中的 .lldbinit
文件。 请注意,这是一个隐藏文件,如果看不到该文件,可以使用以下快捷方式在你的查找器中显示隐藏文件:
1 | shift + command + . |
如果在 finder 中启用了显示隐藏文件,仍然没有找到该文件,可以在根目录下使用下面的终端命令创建一个:
1 | touch ~/.lldbinit |
之后,打开 .lldbinit
文件将整个别名命令粘贴到文件中。这样,Xcode 将在每次启动新的调试会话时执行别名命令。
Pro Tip: 如果不想在每次更新
.lldbinit
文件时都重新启动调试会话,可以使用以下命令重新加载它:
1 | command source ~/.lldbinit |
3. 添加带参数的 LLDB 命令
接着,让我们尝试添加一个能够接受参数的命令。 在上面 greet 命令的基础上进行修改,使其能够接受一个字符串并且打印出问候消息。
这一次,我们将使用 command regex
LLDB 命令。它结构如下:
1 | command regex [command_name] 's/[regex]/expr -l Swift -O -- [swift_code]/' |
这里对 regex 命令的工作原理不做详细描述。 通常,是将 [regex] 替换为正则表达式语句 (.+),然后在 Swift 代码中使用 %1 表示参数。
更新 greet
,如下所示:
1 | command regex greet 's/(.+)/expr -l Swift -O -- print("Hello \(%1)!")/' |
假设 name = "Swift Senpai"
执行结果如下:
1 | (lldb) greet name |
到这里,你可能会问:如果我需要传入多个参数怎么办? 答案其实很简单。
首先,将多个 (.+)
添加到正则表达式语句并用空格分隔每个 (.+)
。 之后,使用 %2
, %3
, %4
… 来表示 Swift 代码中的每个参数。
将 greet
命令更新为支持两个参数,如下:
1 | command regex greet 's/(.+) (.+)/expr -l Swift -O -- print("Hello (%1) and (%2)!")/' |
假设 name1 = "Swift Senpai"
和 name2 = "iOS developers"
,使用该命令,结果如下:
1 | (lldb) greet name1 name2 |
到这里,我们已经了解了如何添加带有多个参数的自定义 LLDB 命令。 下面,将向你展示如何将多行 Swift 函数转换为自定义 LLDB 命令。
将复杂的 Swift 代码转换为 LLDB 命令
通过前面的介绍,我们知道添加自定义 Swift 代码作为 LLDB 命令,必须在一行中完成。因此,如果有一个多行的 Swift 函数,我们必须先将其转换为单行,然后才能将其添加到 .lldbinit
文件中。
比如要添加下面这个将 RGB 值转换为十六进制值的 Swift 函数:
1 | func hex(r: Int, g: Int, b: Int) { |
注意: 上面的代码注释使用的是 /* */
而不是 //
,这是为了确保将 Swift 代码转换为单行后不会中断。
下面我们需要将 Swift 代码转换为一行,操作流程如下:
- 为每个函数参数定义一个变量。
- 将
%1
、%2
、%3
… 分配给每个定义的变量。 - 在每个语句的末尾添加
;
。
更新后的 Swift 代码如下:
1 | let r = %1; |
下面,我们需要将 Swift 代码转换为一行,我比较喜欢使用这个免费在线工具进行单行转换
将代码转换为单行后,就可以进行构造正则表达式命令:
1 | command regex hex 's/(.+) (.+) (.+)/expr -l Swift -O -- let r = %1; let g = %2; let b = %3; if (r >= 0 && r <= 255) && (g >= 0 && g <= 255) && (b >= 0 && b <= 255) { let rgb:Int = r<<16 | g<<8 | b<<0; let hex = String(format:"#%06x", rgb); print(hex); } else { print("Invalid input value"); }/' |
将命令粘贴到 .lldbinit
文件中,然后就可以使用了。
实用的自定义 LLDB 命令
在学会了如何向 LLDB 调试器中添加自定义命令,那么添加什么样的自定义 LLDB 命令最实用呢?
我个人认为下面的自定义命令非常实用。可以在 Xcode 控制台中将任何 JSON 可序列化类型(例如字典、数组、数据等)打印为 JSON 字符串。 可以参考这篇文章。
另外,我也很喜欢本文讨论的一系列自定义命令,我们可以使用它们来动态修改 UI 元素的颜色,而无需重新构建项目。
总结
本文只是对 LLDB 调试器功能做了简单介绍。如果你是刚刚接触到 LLDB,希望这篇文章能帮助你开始探索这个神奇的调试工具。
本文已在公众号「Swift 社区」发布,如需转载请加微信:fzhanfei,备注转载开白