>

基本 Xcode 中常见的调试方式 LLDB 都支持,可以使

- 编辑:澳门博发娱乐官网 -

基本 Xcode 中常见的调试方式 LLDB 都支持,可以使

LLDB是Xcode默认的调试器,与LLVM编译器一起是Xcode中最重要的部分,可以使用LLDB的一些命令来帮助我们调试bug。

LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。平时用Xcode运行程序,实际走的都是LLDB。熟练使用LLDB,可以让你debug事半功倍

LLDB简介

po self.view.frame

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

  1. 关于.lldbinit

LLDB基础知识

LLDB是开源的, 内置于Xcode的Debugger 其可以安装C++或者Python插件. LLDB绑定在Xcode内部, 存在于主窗口底部的控制台中. 平时用Xcode调试程序, 实际走的都是LLDB. 熟练使用LLDB, 可以让你debug事半功倍.

(origin = (x = 0, y = 0), size = (width = 320, height = 568))

图片 1LLDB

LLDB每次启动都会加载~.lldbinit文件,一些全局初始化的设置可以写在这个文件里面。

LLDB控制台

Xcode中内嵌了LLDB控制台,在Xcode中代码的下方,我们可以看到LLDB控制台。

图片 2

LLDB控制台平时会输出一些log信息。如果我们想输入命令调试,必须让程序进入暂停状态。让程序进入暂停状态的方式主要有2种:
断点或者watchpoint: 在代码中设置一个断点(watchpoint),当程序运行到断点位置的时候,会进入stop状态
直接暂停,控制台上方有一个暂停按钮,上图红框已标出,点击即可暂停程序

 

(origin = (x = 0, y = 0), size = (width = 320, height = 568))

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

~.lldbinit默认是不存在的,可以使用touch 命令创建

LLDB语法

在使用LLDB之前,我们来先看看LLDB的语法,了解语法可以帮助我们清晰的使用LLDB:
<command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument [argument...]]

一眼看上去可能比较迷茫,给大家解释一下:

  1. <command>(命令)和<subcommand>(子命令):LLDB调试命令的名称。命令和子命令按层级结构来排列:一个命令对象为跟随其的子命令对象创建一个上下文,子命令又为其子命令创建一个上下文,依此类推。
  2. <action>:执行命令的操作
  3. <options>:命令选项
  4. <arguement>:命令的参数
  5. []:表示命令是可选的,可以有也可以没有

举个例子,假设我们给main方法设置一个断点,我们使用下面的命令:
breakpoint set -n main

这个命令对应到上面的语法就是:
command:breakpoint表示断点命令
action:set表示设置断点
option:-n表示根据方法name设置断点
arguement:mian表示方法名为mian

1.Xcode中的LLDB控制台常用的快捷键

例如 :

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

图片 3

原始(raw)命令

LLDB支持不带命令选项(options)的原始(raw)命令,原始命令会将命令后面的所有东西当做参数(arguement)传递。不过很多原始命令也可以带命令选项,当你使用命令选项的时候,需要在命令选项后面加--区分命令选项和参数。

e.g: 常用的expression就是raw命令,一般情况下我们使用expression
打印一个东西是这样的:

(lldb) expression count
(int) $2 = 4

当我们想打印一个对象的时候。需要使用-O
命令选项,我们应该用--
将命令选项和参数区分:

(lldb) expression -O -- self
<ViewController: 0x7f9000f17660>

快捷键功能

命令

暂停/继续

cmd + ctrl + Y

控制台显示/隐藏

cmd + Y

光标切换到控制台

cmd + shift + C

清空控制台

cmd + K

step over

F6

step into

F7

step out

F8

图片 4

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

唯一匹配原则

LLDB的命令遵循唯一匹配原则:假如根据前n个字母已经能唯一匹配到某个命令,则只写前n个字母等效于写下完整的命令。e.g: 前面提到我设置断点的命令,我们可以使用唯一匹配原则简写,下面2条命令等效:

breakpoint set -n main
br s -n main

 

那么接下来这正是我们要解决的问题。

程序crash的时候,可以使用此命令来打印线程堆栈调用信息。

~/.lldbinit

LLDB有了一个启动时加载的文件~/.lldbinit
,每次启动都会加载。所以一些初始化的事儿,我们可以写入~/.lldbinit
中,比如给命令定义别名等。但是由于这时候程序还没有真正运行,也有部分操作无法在里面玩,比如设置断点。

2.唯一匹配原则

首先在终端输入三个命令

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

图片 5

LLDB命令

LLDB命令遵循唯一匹配原则:加入前n个字母已经能够确定唯一匹配到一个命令, 则只写前n个字母等效于写下完整的命令

touch ~/.lldbinit

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

3.image lookup -a 地址命令

expression

expression命令的作用是执行一个表达式,并将表达式返回的结果输出。expression的完整语法是这样的:

expression <cmd-options> -- <expr>
  1. <cmd-options>:命令选项,一般情况下使用默认的即可,不需要特别标明。
  2. --: 命令选项结束符,表示所有的命令选项已经设置完毕,如果没有命令选项,--可以省略
  3. <expr>: 要执行的表达式

expression是LLDB里面最重要的命令都不为过。因为他能实现2个功能。

  • 执行某个表达式。
    我们在代码运行过程中,可以通过执行某个表达式来动态改
    变程序运行的轨迹。假如我们在运行过程中,突然想把self.view颜色改成红色,
    看看效果。我们不必写下代码,重新run,只需暂停程序,用expression
    改变颜色,再刷新一下界面,就能看到效果
// 改变颜色 
(lldb) expression -- self.view.backgroundColor = [UIColor redColor] 
// 刷新界面
 (lldb) expression -- (void)[CATransaction flush]
  • 将返回值输出。
    也就是说我们可以通过expression来打印东西。
    假如我们想打印self.view:
(lldb) expression -- self.view
 (UIView *) $1 = 0x00007fe322c18a10

 

echo display @import UIKit >> ~/.lldbinit

  • 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个断点加一个条件

当程序crash的时候,可以用此命令来查看某个地址对应在程序中的位置

p & print & call

一般情况下,我们直接用expression还是用得比较少的,更多时候我们用的是p
printcall。这三个命令其实都是expression --的别名(--表示不再接受令选项)

1.print: 打印某个东西,可以是变量和表达式
2.p: 可以看做是print的简写
3.call: 调用某个方法。

表面上看起来他们可能有不一样的地方,实际都是执行某个表达式(变量也当做表达式),将执行的结果输出到控制台上。所以你可以用p调用某个方法,也可以用call
打印东西e.g: 下面代码效果相同:

(lldb) expression -- self.view
(UIView *) $5 = 0x00007fb2a40344a0
(lldb) p self.view
(UIView *) $6 = 0x00007fb2a40344a0
(lldb) print self.view
(UIView *) $7 = 0x00007fb2a40344a0
(lldb) call self.view
(UIView *) $8 = 0x00007fb2a40344a0
(lldb) e self.view
(UIView *) $9 = 0x00007fb2a40344a0

根据唯一匹配原则,如果你没有自己添加特殊的命令别名。e也可以表示expression的意思。原始命令默认没有命令选项,所以e也能带给你同样的效果

3.~/.lldbinit

echo target stop-hook add -o "target stop-hook disable" >> ~/.lldbinit

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

比如,

po

我们知道,OC里所有的对象都是用指针表示的,所以一般打印的时候,打印出来的是对象的指针,而不是对象本身。如果我们想打印对象。我们需要使用命令选项:-O。为了更方便的使用,LLDB为expression -O --定义了一个别名:po

(lldb) expression -- self.view
(UIView *) $13 = 0x00007fb2a40344a0
(lldb) expression -O -- self.view
<UIView: 0x7fb2a40344a0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fb2a4018c80>>
(lldb) po self.view
<UIView: 0x7fb2a40344a0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fb2a4018c80>>

还有其他很多命令选项,不过我们一般用得比较少,所以我就不具体的一一介绍了,如果想了解,在LLDB控制台上输入:help expression
即可查到expression所有的信息

LLDB有一个启动时加载的文件’~/.lldbinit’, 每次启动都会加载. 所以一些初始化的事我们可以统一放在~/.lldbinit中, 比如给命令定义别名等. 但是由于这时候程序还没有真正运行, 也有部分操作在这里无法运行, 比如设置断点.

图片 6

图片 7调试断点

图片 8用image命令打印crash堆栈信息(此处直接打印出错位置的地址)

thread

thread backtrace

 

输完命令后没有任何提示。那你就成功了。重新运行项目

  • cContinue,继续执行
  • nStepOver,一步一步执行方法
  • sStepInto,进入方法调用里面
  • finishStepOut,跳出方法调用
  1. watchpoint set variable self->变量名 命令

& bt

有时候我们想要了解线程堆栈信息,可以使用thread backtrace
thread backtrace作用是将线程的堆栈打印出来。我们来看看他的语法

thread backtrace [-c <count>] [-s <frame-index>] [-e <boolean>]

thread backtrace后面跟的都是命令选项:
-c:设置打印堆栈的帧数(frame)
-s:设置从哪个帧(frame)开始打印
-e:是否显示额外的回溯实际上这些命令选项我们一般不需要使用。

e.g: 当发生crash的时候,我们可以使用thread backtrace

查看堆栈调用

(lldb) thread backtrace
* thread #1: tid = 0xdd42, 0x000000010afb380b libobjc.A.dylib`objc_msgSend + 11, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
  frame #0: 0x000000010afb380b libobjc.A.dylib`objc_msgSend + 11 
* frame #1: 0x000000010aa9f75e TLLDB`-[ViewController viewDidLoad](self=0x00007fa270e1f440, _cmd="viewDidLoad") + 174 at ViewController.m:23
  frame #2: 0x000000010ba67f98 UIKit`-[UIViewController loadViewIfRequired] + 1198 
  frame #3: 0x000000010ba682e7 UIKit`-[UIViewController view] + 27   
  frame #4: 0x000000010b93eab0 UIKit`-[UIWindow addRootViewControllerViewIfPossible] + 61
  frame #5: 0x000000010b93f199 UIKit`-[UIWindow _setHidden:forced:] + 282
  frame #6: 0x000000010b950c2e UIKit`-[UIWindow makeKeyAndVisible] + 42

我们可以看到crash发生在-[ViewController viewDidLoad]
中的第23行,只需检查这行代码是不是干了什么非法的事儿就可以了。

LLDB还为backtrace专门定义了一个别名:bt,他的效果与thread backtrace相同,如果你不想写那么长一串字母,直接写下bt
即可:

(lldb) bt

4.LLDB命令, expression

看到这个,你就成功了。

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

此命令可用来跟踪变量值的变化,每当变量的值被修改的时候,都会触发一次。

thread return

Debug的时候,也许会因为各种原因,我们不想让代码执行某个方法,或者要直接返回一个想要的值。这时候就该thread return上场了。

thread return [<expr>]

thread return可以接受一个表达式,调用命令之后直接从当前的frame返回表达式的值。

e.g: 我们有一个someMethod方法,默认情况下是返回YES。我们想要让他返回NO

图片 9

我们只需在方法的开始位置加一个断点,当程序中断的时候,输入命令即可:

(lldb) thread return NO

效果相当于在断点位置直接调用return NO;不会执行断点后面的代码

expression命令的作用是执行一个表达式, 并将结果输出. 说expression是LLDB中最重要的命令都不为过. 因为它能实现两个功能:

现在运行到断点处,po self.view.frame

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

    图片 10打印self.view.bounds

  • expr + 变量赋值这个会实际改变变量的值

    图片 11运行时改变了 num 的值

  • expr + 方法调用最神奇的莫过于这个,在运行时直接调用指定方法,给运行时加一些“行为”,比如

比如:给namea属性添加一个watchpoint.

c & n & s & finish

一般在调试程序的时候,我们经常用到下面这4个按钮:

图片 12

用触摸板的孩子们可能会觉得点击这4个按钮比较费劲。其实LLDB命令也可以完成上面的操作,而且如果不输入命令,直接按Enter键,LLDB会自动执行上次的命令。按一下Enter就能达到我们想要的效果,有木有顿时感觉逼格满满的!!!
我们来看看对应这4个按钮的LLDB命令:

1.c/continue/thread continue: 这三个命令效果都等同于上图中第一个按钮的。表示程序继续运行
2.n/next/thread step-over: 这三个命令效果等同于上图第二个按钮。表示单步运行
3.s/step/thread step-in: 这三个命令效果等同于上图第三个按钮。表示进入某个方法
4.finish/step-out: 这两个命令效果等同于第四个按钮。表示直接走完当前方法,返回到上层frame

1, 执行某个表达式. 我们在代码运行过程中, 可以通过执行某个表达式来动态的改变程序的运行轨迹. 比如想要突然改掉view的颜色, 看看效果, 不必重写代码, 重新run. 只需要暂停一下, 用expression改变颜色, 再刷新一下界面就能看到效果.

po self.view.frame

图片 13在ViewController出现时,给这个断点添加一个行为

图片 14添加一个watchpoint

thread其他不常用的命令

thread 相关的还有其他一些不常用的命令,这里就简单介绍一下即可,如果需要了解更多,可以使用命令help thread查阅

1.thread jump: 直接让程序跳到某一行。由于ARC下编译器实际插入了不少retain,release命令。跳过一些代码不执行很可能会造成对象内存混乱发生crash。
2.thread list: 列出所有的线程
3.thread select: 选择某个线程
4.thread until: 传入一个line的参数,让程序执行到这行的时候暂停
5.thread info: 输出当前线程的信息

当然, 也可以修改某个变量的值.

(origin = (x = 0, y = 0), size = (width = 320, height = 568))

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

当点击按钮,修改namea属性的时候

frame

前面我们提到过很多次frame(帧)。可能有的朋友对frame这个概念还不太了解。随便打个断点

图片 15

我们在控制台上输入命令bt,可以打印出来所有的frame。如果仔细观察,这些frame和左边红框里的堆栈是一致的。平时我们看到的左边的堆栈就是frame。

```

(origin = (x = 0, y = 0), size = (width = 320, height = 568))

图片 16每次蓝色的VC出现时,会执行segue,弹出黄色的VC

图片 17在按钮点击事件中修改namea属性的值图片 18watchpoint被触发

frame variable

平时Debug的时候我们经常做的事就是查看变量的值,通过frame variable
命令,可以打印出当前frame的所有变量

(lldb) frame variable(ViewController *) self = 0x00007fa158526e60(SEL) _cmd = "text:"(BOOL) ret = YES(int) a = 3

可以看到,他将self,_cmd,ret,a等本地变量都打印了出来,如果我们要需要打印指定变量,也可以给frame variable传入参数:

(lldb) frame variable self->_string(NSString *) self->_string = nil

不过frame variable
只接受变量作为参数,不接受表达式,也就是说我们无法使用frame variable self.string
,因为self.string
是调用string
的getter
方法。所以一般打印指定变量,我更喜欢用p
或者po

//改变颜色

一目了然。

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

点击控制台第六个带向上箭头的按钮两次,第一次会跳到namea属性定义的地方,第二次会跳转到触发这次watchpoint的具体位置:如下:

其他不常用命令

一般frame variable
打印所有变量用得比较多,frame还有2个不怎么常用的命令:
frame info
: 查看当前frame的信息
(lldb) frame infoframe #0: 0x0000000101bf87d5 TLLDB`-[ViewController text:](self=0x00007fa158526e60, _cmd="text:", ret=YES) + 37 at ViewController.m:38

frame select
: 选择某个frame
(lldb) frame select 1frame #1: 0x0000000101bf872e TLLDB`-[ViewController viewDidLoad](self=0x00007fa158526e60, _cmd="viewDidLoad") + 78 at ViewController.m:23 20 21 - (void)viewDidLoad { 22 [super viewDidLoad];-> 23 [self text:YES]; 24 NSLog(@"1"); 25 NSLog(@"2"); 26 NSLog(@"3");

当我们选择frame 1的时候,他会把frame1的信息和代码打印出来。不过一般我都是直接在Xcode左边点击某个frame,这样更方便

expression — self.view.backgroundColor = UIColor.red

那么不先用了怎么办呢,只要删掉.lldbinit就好了。

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

图片 19属性namea定义的地方图片 20属性namea被修改的地方(watchpoint触发点)

breakpoint

调试过程中,我们用得最多的可能就是断点了。LLDB中的断点命令也非常强大

//刷新界面

1.打开终端,

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

    图片 21isYesOrNo 本来为YES,但是通过 thread return 直接让其值返回NO

  1. thread return 0/1 命令

breakpoint set

breakpoint set
命令用于设置断点,LLDB提供了很多种设置断点的方式:
***使用-n
根据方法名设置断点:*******
e.g: 我们想给所有类中的viewWillAppear:
设置一个断点:
(lldb) breakpoint set -n viewWillAppear: Breakpoint 13: 33 locations.

***使用-f
指定文件*******
e.g: 我们只需要给ViewController.m
文件中的viewDidLoad
设置断点:
(lldb) breakpoint set -f ViewController.m -n viewDidLoad Breakpoint 22: where = TLLDB`-[ViewController viewDidLoad] + 20 at ViewController.m:22, address = 0x000000010272a6f4

这里需要注意,如果方法未写在文件中(比如写在category文件中,或者父类文件中),指定文件之后,将无法给这个方法设置断点。
***使用-l
指定文件某一行设置断点*******
e.g: 我们想给ViewController.m
第38行设置断点
(lldb) breakpoint set -f ViewController.m -l 38Breakpoint 23: where = TLLDB`-[ViewController text:] + 37 at ViewController.m:38, address = 0x000000010272a7d5

***使用-c
设置条件断点*******
e.g:text:
方法接受一个ret
的参数,我们想让ret == YES
的时候程序中断:
(lldb) breakpoint set -n text: -c ret == YESBreakpoint 7: where = TLLDB`-[ViewController text:] + 30 at ViewController.m:37, address = 0x0000000105ef37ce

***使用-o
设置单次断点*******
e.g: 如果刚刚那个断点我们只想让他中断一次:
(lldb) breakpoint set -n text: -o'breakpoint 3': where = TLLDB`-[ViewController text:] + 30 at ViewController.m:37, address = 0x000000010b6f97ce

expression — (void)CATransaction.flush    (e (void)[CATransaction flush] )  //刷新UI

2输入 rm ~/.lldbinit

运行时直接查看变量的值

次命令会直接返回0/1,不再执行下面的语句。

breakpoint command

有的时候我们可能需要给断点添加一些命令,比如每次走到这个断点的时候,我们都需要打印self
对象。我们只需要给断点添加一个po self
命令,就不用每次执行断点再自己输入po self

```

回车,无反应就哦了。

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

如下:

breakpoint command add

breakpoint command add
命令就是给断点添加命令的命令。
e.g: 假设我们需要在ViewController
的viewDidLoad
中查看self.view
的值我们首先给-[ViewController viewDidLoad]
添加一个断点
(lldb) breakpoint set -n "-[ViewController viewDidLoad]"'breakpoint 3': where = TLLDB`-[ViewController viewDidLoad] + 20 at ViewController.m:23, address = 0x00000001055e6004

可以看到添加成功之后,这个breakpoint
的id为3,然后我们给他增加一个命令:po self.view

(lldb) breakpoint command add -o "po self.view" 3

-o
完整写法是--one-liner
,表示增加一条命令。3
表示对id为3
的breakpoint
增加命令。添加完命令之后,每次程序执行到这个断点就可以自动打印出self.view
的值了
如果我们一下子想增加多条命令,比如我想在viewDidLoad
中打印当前frame的所有变量,但是我们不想让他中断,也就是在打印完成之后,需要继续执行。我们可以这样玩:
(lldb) breakpoint command add 3Enter your debugger command(s). Type 'DONE' to end.> frame variable> continue> DONE

输入breakpoint command add 3
对断点3增加命令。他会让你输入增加哪些命令,输入'DONE'表示结束。这时候你就可以输入多条命令了
多次对同一个断点添加命令,后面命令会将前面命令覆盖

2,将返回值输出. 也就是说我们可以用expression打印东西. 比如:

现在我们来刨根问底的看看它是怎么做到的。。

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

图片 22用thread return 0 命令直接将按钮点击事件返回图片 23点击第三个继续执行按钮即可

breakpoint command list

如果想查看某个断点已有的命令,可以使用breakpoint command list
。e.g: 我们查看一下刚刚的断点3已有的命令
(lldb) breakpoint command list 3'breakpoint 3': Breakpoint commands: frame variable continue

可以看到一共有2条命令,分别为frame variable
和continue

```

首先:"po" : 我们知道,OC里所有的对象都是用指针表示的,所以一般打印的时候,打印出来的是对象的指针,而不是对象本身。如果我们想打印对象。我们需要使用命令选项:-O。为了更方便的使用,LLDB为expression -O --定义了一个别名:po.

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

6.expression -- 表达式 命令

breakpoint command delete

有增加就有删除,breakpoint command delete
可以让我们删除某个断点的命令e.g: 我们将断点3中的命令删除:
(lldb) breakpoint command delete 3(lldb) breakpoint command list 3Breakpoint 3 does not have an associated command.

可以看到删除之后,断点3就没有命令了

expression — self.view

LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。平时用Xcode运行程序,实际走的都是LLDB。

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

次命令可用来修改变量的值,以及执行表达式

breakpoint list

如果我们想查看已经设置了哪些断点,可以使用breakpoint list
e.g:
(lldb) breakpoint listCurrent breakpoints:4: name = '-[ViewController viewDidLoad]', locations = 1, resolved = 1, hit count = 0 4.1: where = TLLDB`-[ViewController viewDidLoad] + 20 at ViewController.m:23, address = 0x00000001055e6004, resolved, hit count = 0

我们可以看到当前只有一个断点,打在-[ViewController viewDidLoad]
上,id是4

```

LLDB有了一个启动时加载的文件~/.lldbinit,每次启动都会加载。所以一些初始化的事儿,我们可以写入~/.lldbinit中,比如给命令定义别名等。但是由于这时候程序还没有真正运行,也有部分操作无法在里面玩,比如设置断点。

  • breakpoint command add -s python n给第n个断点添加python代码

如下

breakpoint disable/enable

有的时候我们可能暂时不想要某个断点,可以使用breakpoint disable
让某个断点暂时失效e.g: 我们来让刚刚的断点4失效
(lldb) breakpoint disable 41 breakpoints disabled.

输入完命令之后,显示断点已经失效
当我们又需要这个断点的时候,可以使用breakpoint enable
再次让他生效e.g: 重新启用断点4
(lldb) breakpoint enable 41 breakpoints enabled.

 

更多关于LLDB可以查看 浅谈LLDB

图片 24给断点1添加简单的python代码,每次停下来时,会执行这段代码

图片 25

breakpoint delete

如果我们觉得这个断点以后再也用不上了,可以用breakpoint delete
直接删除断点.e.g: 删除断点4
(lldb) breakpoint delete 41 breakpoints deleted; 0 breakpoint locations disabled.

如果我们想删除所有断点,只需要不指定breakpoint delete
参数即可
(lldb) breakpoint delete About to delete all breakpoints, do you want to do that?: [Y/n] yAll breakpoints removed. (1 breakpoint)

删除的时候他会提示你,是不是真的想删除所有断点,需要你再次输入Y
确认。如果想直接删除,不需要他的提示,使用-f
命令选项即可
(lldb) breakpoint delete -fAll breakpoints removed. (1 breakpoint)

实际平时我们真正使用breakpoint
命令反而比较少,因为Xcode已经内置了断点工具。我们可以直接在代码上打断点,可以在断点工具栏里面查看编辑断点,这比使用LLDB命令方便很多。不过了解LLDB相关命令可以让我们对断点理解更深刻。如果你想了解怎么使用Xcode设置断点,可以阅读这篇文章《Xcode中断点的威力》

5.p, po, print, call

touch ~/.lldbinit

  • breakpoint command add -F "python文件名"."python方法名" n给第n个断点添加导入的 python 文件中的方法调用

再比如程序运行中修改某个控件或view的样式

watchpoint

breakpoint
有一个孪生兄弟watchpoint
。如果说breakpoint
是对方法生效的断点,watchpoint
就是对地址生效的断点
如果我们想要知道某个属性什么时候被篡改了,我们该怎么办呢?有人可能会说对setter方法打个断点不就行了么?但是如果更改的时候没调用setter方法呢?这时候最好的办法就是用watchpoint
。我们可以用他观察这个属性的地址。如果地址里面的东西改变了,就让程序中断

一般情况下, 我们直接使用expression还是比较少的,更多时候我们用的是p,print,call.这三个命令其实都是`expression -`的别名(`-`表示不再接受命令选项).

如果~/.lldbinit存在,使用touch指令可更改这个文件或目录的日期时间,包括存取时间和更改时间;

本文由胜博发-编程发布,转载请注明来源:基本 Xcode 中常见的调试方式 LLDB 都支持,可以使