iOS 调试技巧:如何利用 LLDB 来 Debug

初步认识LLDB

LLDB是XCode内置的为我们开发者提供的调试工具。至于还不懂什么是调试的,百度一下概念吧,笔者也不知如何描述。看看下图吧,应该就可以大概明白什么是调试了!

blob.png

我们加了断点,然后在运行到断点处就停了下来,接下来我们看到lldb这里了吗?我们可以通过lldb所提供的命令来操作。

基本调试操作

从上图中,我们八个按钮,我们讲讲前五个按钮:

  • 第一个按钮点击就会收起这一栏目了,也就看不见了。

  • 第二个按钮:如果为蓝色,就是断点有效。如果点击它变成灰色,就是所有断点不起作用。

  • 第三个按钮:是继续的意思,会让程序从断点处恢复继续往下运行,我们点了这个按钮后,应用就会恢复正常运行状态。

  • 第四个按钮是:单步执行的意思,每点这个按钮一次,程序就会从我们断点开始的地方,向下执行一步。

  • 第五个按钮是:进入执行的意思,简单来说就是如果我们当前的断点在一个函数调用上,把么断点会继续进入这个函数的内部进行调试。

  • 第六个按钮是:跳出的意思, 就是如果我们当前在一个函数中,它会跳出当前的函数,回到函数的调用处。

常用p、po、call命令

先看下图:

blob.png

以下是输入help命令时打印出来的,可以看看这四者有什么不同:

1
2
3
4
5
6
7
8
9
10
11
12
p         -- ( 'expression --' )  Evaluate an expression (ObjC++ or Swift)  in
                the current program context, using user defined variables and
                variables currently  in  scope.
po        -- ( 'expression -O  -- ' )  Evaluate an expression (ObjC++ or Swift)
                in  the current program context, using user defined variables and
                variables currently  in  scope.
print     -- ( 'expression --' )  Evaluate an expression (ObjC++ or Swift)  in
                the current program context, using user defined variables and
                variables currently  in  scope.
call      -- ( 'expression --' )  Evaluate an expression (ObjC++ or Swift)  in
                the current program context, using user defined variables and
                variables currently  in  scope.

从官方的描述来看,p、print、call是一样的,但是po就不太一样了,输入一样但是输出不一样。po的输出的是具体对象的内容。

如果想要按照特定的格式来打印,如下:

1
2
3
4
5
6
7
8
(lldb) p/s blogName
(__NSCFConstantString *) $9 = @ "标哥的技术博客"
(lldb) p/x blogName
(__NSCFConstantString *) $10 = 0x000000010921c0a8 @ "标哥的技术博客"
(lldb) p/t blogName
(__NSCFConstantString *) $11 = 0b0000000000000000000000000000000100001001001000011100000010101000 @ "标哥的技术博客"
(lldb) p/a blogName
(__NSCFConstantString *) $12 = 0x000000010921c0a8 @ @ "标哥的技术博客"

关于这个规则问题,请查阅打印输出格式化

lldb声明变量

我们可以使用e命令定义变量,然后在调试中使用。看如下的例子:

1
2
3
4
5
6
7
8
9
10
(lldb) e NSString *$str = @ "http://www.henishuo.com"
(lldb) po $str
http: //www.henishuo.com
 
(lldb) e int $count = 10
(lldb) p $count
(int) $count = 10
(lldb) e NSArray *itemArray = @[@ "Test" , @ "Demo" , @ "huangyibiao" ]
(lldb) po $count
10

我们使用e声明了str变量,然后下面就可以使用了。我们看到通过p命令打印出来的都是开头的变量了吗?我们在声明和使用时也需要加上$符号,与PHP一样!

在调试时,有时候想临时计算一下某个值来比较时,就可以通过这种方式来实现了,再也不用到源代码处添加上声明实现然后添加一句打印了,是否便利了很多?

调用变量的API

当我们在断点处,定义了blogName变量了,因此我们可以通过调试命令来调用

1
2
3
4
5
(lldb) po [blogName uppercaseString]
标哥的技术博客
 
(lldb) po [blogName substringFromIndex:2]
的技术博客

强转返回值类型

当我们调用API返回值类型不指定时,有时候所打印出来的东西是我们看不懂的,比如下面的获取结果应该是“标”字,但是不同类型打印结果却不一样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(lldb) po [blogName characterAtIndex:0]
26631
 
(lldb) po (unsigned int)[blogName characterAtIndex:0]
26631
 
(lldb) po (char)[blogName characterAtIndex:0]
'a'
 
(lldb) po (NSString *)[blogName characterAtIndex:0]
0x0000000000006807
 
(lldb) po (unichar)[blogName characterAtIndex:0]
U+6807 u '标'

加断点

如果我们不是在一开始就添加所有的断点,而在调试开始后,想给其它地方加个断点,那么我们可以很方便地通过命令添加断点:

1
2
(lldb) b ? 33
Breakpoint 9: where = OCLLDBDebugDemo`-[ViewController onButtonClicked:] + 53 at ViewController.m:33, address = 0x000000010921a6d5

这是在当前类文件下的33行添加一个断点,添加成功后会有提示,如这里的提示就是成功地在33行添加了断点。当然,添加断点的方式也有好几种,如:

1
2
(lldb) b ?-[ViewController onButtonClicked:]
Breakpoint 4: where = OCLLDBDebugDemo`-[ViewController onButtonClicked:] + 53 at ViewController.m:33, address = 0x000000010921a6d5

实际也是在33行添加断点。不过我们若要使用动态添加断点,就使用b命令加行号就可以了,这种最简单了。

设置断点触发条件

看下图,笔者是怎么设置触发条件的:

blob.png

我们在NSLog这一行,设置了条件,只有当条件满中时,才会进入断点,不过这里并没有让它进入断点,而条件满足时就发出声音并打印提示语。

这种应用场景主要是在循环遍历数据时,想要断点跟踪就只能通过这种方式了,除非添加NSLog打印,但是这种需要手动添加代码,在调试时才想到要添加一些打印语句,这时候又得重新运行,这太慢了。如果懂得如何设置断点条件,那么就能满足我们的需求了,直接可以设置条件。

常用打印视图层次结构

当我们想要知道某个视图的结构时,可以通过调用recursiveDescription方法来打印出来,那么其结构就一目了然了:

1
2
(lldb) po [self.view recursiveDescription] ? | ? | ? ?| ? | ? ?| ? ?|(layer)
  ? | ? |

临时刷新界面UI

本demo中,最开始按钮的背景颜色是blueColor,现在我们要在调试过程中修改其背景色为红色,并刷新界面。执行下面的命令行,App界面的按钮背景颜色是:

blob.png

(lldb) e ((UIButton *)sender).backgroundColor = [UIColor redColor]
(UICachedDeviceRGBColor *) $41 = 0x00007fdd10715b00
(lldb) e (void)[CATransaction flush]

执行上面的命令后,App界面的按钮背景颜色是:

blob.png

这种做法很有用的哦。当我们在调试UI时,因为颜色类似而不容易区分出来,但是我们可以在调试时通过这样的方式来修改背景色,就不用给源代码写相应的代码来重新运行看效果了。

在调试下运行上面的命令后,按钮的背景颜色就变成了红色了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值