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