Xcode 调试之 LLDB

LLDB 是 Xcode 中的默认调试器,支持调试 C、Objective-C、C++,用 LLDB 调试代码的好处不必多说,基本 Xcode 中常见的调试方式 LLDB 都支持,但 LLDB 还可以在运行时写和运行一些简单代码、运行 Python 代码来扩展调试的方式。

Xcode 调试之 LLDB_第1张图片
LLDB

现在让我们来总结写 LLDB 都有哪些调试方式吧~

打印

我们最常用的可能就是进行打印操作,在打下断点,程序暂时停止,在 console 中写命令打印一些变量的值:

  • po oc对象
    会调用oc对象的description方法,将这个对象打印出来
  • p 基本数据类型
    可以使用 print、或其简写 p 打印一些基本数据类型

Help

  • help 命令
    下面讲的所有命令都可以通过 help 查看其具体含义、信息

Breakpoint

可以直接用写命令的方式打断点、调试、编辑断点信息:

  • b 某文件.m:30
    给 某文件的第30行打下一个断点

  • br l
    列出当前工程的所有断点信息

  • br delete n
    删除第n个断点

  • br enable n
    使第n个断点有效

  • br disable n
    使第n个断点失效

  • br set -n 某方法
    设置关于这个方法的符号断点,在调用这个方式时,程序都会暂停

  • br mod -c "某条件" n
    设置条件断点,给第n个断点加一个条件

在断点停下后,还可以像按这些键一样,调试断点:


Xcode 调试之 LLDB_第2张图片
调试断点
  • c
    Continue,继续执行
  • n
    StepOver,一步一步执行方法
  • s
    StepInto,进入方法调用里面
  • finish
    StepOut,跳出方法调用

Expression

expr + OC 代码,在运行时可以执行,对于输出一些运行时才会确定的变量十分有用。

  • expr (void) NSLog(@"balhbalh")
    简单的打印操作
  • expr + 结构体
    expr 可以打印结构体的值


    打印self.view.bounds
  • expr + 变量赋值
    这个会实际改变变量的值


    Xcode 调试之 LLDB_第3张图片
    运行时改变了 num 的值
  • expr + 方法调用
    最神奇的莫过于这个,在运行时直接调用指定方法,给运行时加一些“行为”,比如
Xcode 调试之 LLDB_第4张图片
在ViewController出现时,给这个断点添加一个行为

给断点添加了一个行为,执行 expr 后面的方法,然后 continue。
这样每次在ViewController出现时,会执行这个 segue ,推出后面的 Controller,如图:

Xcode 调试之 LLDB_第5张图片
每次蓝色的VC出现时,会执行segue,弹出黄色的VC

Backtrace

  • bt
    当程序 crash 掉时,可以用 bt 查看程序运行时函数调用的堆栈信息
  • bt all
    bt 显示的是当前线程函数调用的信息,可以加 all 显示所有线程的堆栈信息

Thread

可以操作线程,显示当前线程信息,在运行时,直接改变方法调用的返回值

  • thread list
    显示所有线程信息
  • thread select n
    选择第n个线程
  • thread backtrace
    显示当前 thread 的堆栈信息
  • thread backtrace all
    显示所有 thread 的堆栈信息
  • thread until i
    使线程运行,并在第 i 行时停下
  • thread return 返回值
    直接改变当前方法调用的返回值


    Xcode 调试之 LLDB_第6张图片
    isYesOrNo 本来为YES,但是通过 thread return 直接让其值返回NO

Frame

运行时直接查看变量的值

  • frame variable
    如上图,frame variable 直接查看当前变量的值
  • frame variable 变量名
    查看指定变量名的值

Watchpoint

当变量变化时,程序暂停,显示 watchpoint 的变化

  • watchpoint list
    显示当前所有 watchpoint
  • watchpoint set variable 变量名
    给变量设置 watchpoint
  • watchpoint modify -c "条件" n
    给第n个断点添加条件,只有满足条件时,watchpoint 才会触发
  • watchpoint modify -c "" n
    条件置空时,即为给这个 watchpoint 删除条件
  • watchpoint set expression -- 内存地址
    对任意内存地址进行观察

Script

lldb 内置了 Python 的脚本解释器,可以解释运行 Python 代码

  • breakpoint command add -s python n
    给第n个断点添加python代码
Xcode 调试之 LLDB_第7张图片
给断点1添加简单的python代码,每次停下来时,会执行这段代码
  • breakpoint command add -F "python文件名"."python方法名" n
    给第n个断点添加导入的 python 文件中的方法调用

Command

  • command script import "文件路径/文件名"
    导入已有的脚本文件,在调试时可以直接用这个文件
  • command import "文件路径/文件名"
    导入已有的 lldb 调试脚本文件
  • command unalias pf
    删除用户自定义的 aliases
  • command history
    打印在当前运行状态下,lldb 调试时command 历史

示例:

  1. 新建一个 empty 文件,文件后缀名为 py,内容为:
def print_locals(frame, bp_loc, internal_dict):
    variables = frame.GetVariables(False,True,False,True)
    for i in range(0, variables.GetSize()):
        variable = variables.GetValueAtIndex(i)
        print variable

大概意思为,定义一个方法,会将当前的变量一个一个打印下来
frame 指当前堆栈信息,bp_loc 指断点的具体位置,internal_dict 这个python 文件的一些参数信息

2.导入 python 代码
3.给断点加入 python 代码中定义的方法
如图所示:


Xcode 调试之 LLDB_第8张图片
调试断点时,使用一段已有的 python 代码

Alias

当遇到较为复杂的命令,可以给这些命令定义一个别名,每次调用别名即可。

  • command alias "别名" 具体命令
    给具体命令设置一个别名
给 expr 命令加了一个别名 pf

上面的方法存在一个问题,设置的别名只在当前运行过程有效,下次就失效了,怎么持久化呢?
可以将这些命令封装起来,保存在电脑中,每次调试时都可使用。

  • 1.新建 lldbinit 文件,在终端中输入
    $ touch ~/.lldbinit
    $ open ~/.lldbinit


    Xcode 调试之 LLDB_第9张图片
    输入命令,图中定义了一个pf命令

2.重启Xcode,再次编译运行
3.打断点,并输入 pf

这一次只要 .lldbint 文件存在,pf别名就一直可以使用

Chisel 是 Facebook 开源的一款 lldb 命令集合文件,GitHub 地址。我们可以直接使用一些定义好的 lldb 命令来调试程序。
安装十分简单,确保 Mac 已经安装了 homebrew 环境
$ brew update
$ brew install chisel
安装成功后会出现

Xcode 调试之 LLDB_第10张图片
安装成功

并且提示要将框中出现的命令加在刚刚生成的那个 .lldbint 文件中。
重启 Xcode 之后,每次就可以使用这些命令了。
在 lldb 中输入 help,我们发现最下面出现了一些用户自定义命令,这就是 Chisel 中的。
比较常用的有border,给视图加边框;hide,隐藏视图;mask,给视图加遮罩;presponder,显示响应者链……

关于 Xcode 调试的文章先总结到这里,希望以后能继续补充完善

参考文章
Xcode LLDB Tutorial
The LLDB Debugger
Dancing in the Debugger — A Waltz with LLDB

你可能感兴趣的:(Xcode 调试之 LLDB)