Xcode 命令和断点(LLDB调试命令技巧)

绪论
Xcode 中的调试技巧与我们的日常开发息息相关,而这些调试技巧在我们解决Bug时,常常有事半功倍的效果。

LLDB全称Low Level Debugger ,并不是低水平的调试器,而是轻量级的高性能调试器,默认内置于Xcode中。LLDBDebug在编译后就是一个Macho的可执行文件,也可以理解为镜像文件image并不是图像的意思,而是代表镜像。这里跟上我们自己的工程名,即用image定位寻址才是寻找我们自己的代码。

image.png

在上图中,右侧黑色区域就是Log 输出区,在 Log 输出区可以使用一些命令,来辅助调试。接下来将讲解lldb常用命令及一些高级用法。

一: 常用的一般调试命令

//
1.p命令
p 命令是 print 命令的简写,查看基本数据类型的值,但是如果使用p命令查看的是对象,那么只会返回对象的指针地址。
p 命令后面除了可以接 变量、常量,还可以接 表达式。(❌但是不可以使用宏❌)

2.po 命令
po 命令可以理解为打印对象的description。可以打印 常量、变量,打印表达式返回的对象等。
(❌也不可以打印宏❌)

p 和po命令的演示

image.gif

p命令修改变量的演示

image.gif
3.expr 命令
使用e来给给具体的变量赋值

if(self.dataArray.count = 0)
{
NSLog(@“修改成功了!”);
};
//若想让self.dataArray.count = 0进入if判断句。那就要当断点到if的时候。
//在控制台输入e self.dataArray.count = 0回车,继续运行就可以。

4.cell 命令
Xcode 还支持动态调用函数。在控制台执行该命令,可以在不修改代码,不重新编译的情况下,修改界面上的视图。
这里有一个动态将cell 的某个子视图移除的范

5.image 命令
image list 命令可以列出当前App中的所有module(这个module 在后面符号断点时有用到),可以查看某一个地址
对应的代码位置。 除了 image list 还有 image add、image lookup等命令,可以自行查看。 
当遇到crash 时,查看线程栈,只能看到栈帧的地址,使用 image lookup –address 地址可以方便
的定位到这个地址对应的代码行。

image lookup -a用于寻找栈地址对应的代码位置,演示如下:

image.gif

从上图中我们可以看到当程序崩溃时并不能定位到指定的代码位置,使用image寻址命令可以定位到具体的崩溃位置在viewDidLoad方法中的第51行。

image.png
//
6.bt命令
bt 命令 可以打印出线程的堆栈信息,该信息比左侧的Debug Navigator 看到的还要详细一些。
bt 命令是打印当前线程的堆栈信息。
bt All输出所有的信息。

7.x 命令
x命令是查看地址在内存的情况 ,一般查看对象地址和对象的属性地址。
x/4gx命令:打印4个16进制地址。x/4gx  student
x/8gx命令:打印8个16进制地址。x/8gx  student

例如:x student
比如:
x 0x600002bfd110 按回车 会出现下面的这些
0x600002bfd110: e8 06 62 0c 01 00 00 00 00 00 00 00 00 00 00 00  ..b...........
0x600002bfd120: 38 e0 61 0c 01 00 00 00 58 e0 61 0c 01 00 00 00  8.a.....x.a.......

使用bt 命令可以查看函数调用堆栈,然后用命令frame select即可查看对应函数详细,演示如下:

image.gif

上面函数执行的顺序如下:点击登录按钮--验证手机号--验证密码--开始登录。

- (IBAction)login:(UIButton *)sender {
   [self validationPhone];
}

#pragma mark --验证手机号
-(void)validationPhone{
   [self validationPwd];
}

#pragma mark --验证密码
-(void)validationPwd{
   [self startLogin];
}

#pragma mark --开始登陆
-(void)startLogin{
   NSLog(@"------开始登录...------");
}

bt命令的打印信息中,我们可以很清楚看到函数调用顺序,如下图:

image.png

接下来我们执行frame select命令即可以查看函数相关信息,同时配合updown命令追踪函数的调用和被调用关系,演示如下:

image.gif

同时可以frame variable使用很方便的查方法的调用者及方法名称,如下图:

image.png

breakpoint命令
b命令给函数下断点,演示如下图:

image.gif

当我们的断点下成功后,控制台会打印如下信息:
Breakpoint 1: where = LLDBDebug-[ViewController login:] at ViewController.m:53, address = 0x00000001034fb0a0

我们可以看到断点的位置在.m文件的53行,Breakpoint 1这里的1代表的是编号为1的组断点。

使用breakpoint list我们可以看到断点的数量,同时使用breakpoint delete后面跟上组号,即可删除,演示如下:

image.png

使用breakpointc,n,s以及fininsh的命令,对应演示如下:

image.png

我们执行c,n,s以及fininsh的命令,对应演示

image.gif

target stop-hook add -o "frame variable"每次进入断点都会自动打印详细的参数信息,演示如下:

image.gif

二: 特殊自定义断点
符号断点就是 Symbolic Breakpoint,其实是针对某一个特定函数的断点,可以是一个OC函数,也可以是C++函数
添加的地方如下:

image.png

image.png

Symbol 栏可以填 [类名 方法名]或者 直接单个方法名module也是选填项,它就是上面image命令中列出来的module

例如 ,我们如果只填一个viewDidLoad,那么就会在所有类(包括第三方库)的viewDidLoad 处打断点。
符号断点在调试一些没有源码的模块时比较有用,比如调试一个第三方提供的Lib库,或者系统的模块,可以在相应函数处下断点,可以大概调试清楚程序的运行流程,也可以在断点的时候查看到参数信息。

三: LLDB高级用法
我们先来简单看下menthodspviews命令的执行效果,演示如下图:

image.gif

menthods命令可以打印当前对象的属性和方法,如下所示:

(lldb) methods p1
<Person: 0x60000003eac0>:
in Person:
    Properties:
        @property (copy, nonatomic) NSString* name;  (@synthesize name = _name;)
        @property (nonatomic) long age;  (@synthesize age = _age;)
    Instance Methods:
        - (void) eat; (0x1098bf3e0)
        - (void) .cxx_destruct; (0x1098bf4f0)
        - (id) description; (0x1098bf410)
        - (id) name; (0x1098bf430)
        - (void) setName:(id)arg1; (0x1098bf460)
        - (void) setAge:(long)arg1; (0x1098bf4c0)
        - (long) age; (0x1098bf4a0)
(NSObject ...)

pviews命令可以打印当前视图的层级结构,如下所示:

(lldb) pviews
<UIWindow: 0x7fd1719060a0; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x60c000058660>; layer = <UIWindowLayer: 0x60c0000364c0>>
   | <UIView: 0x7fd16fc06d10; frame = (0 0; 414 736); alpha = 0.8; autoresize = W+H; layer = <CALayer: 0x60000003e7e0>>
   |    | <UIButton: 0x7fd16fe0b520; frame = (54 316; 266 53); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x60400003b040>>
   |    |    | <UIButtonLabel: 0x7fd16fe023f0; frame = (117.667 17.6667; 30.6667 18); text = '登录'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x60400008ac80>>
   |    |    |    | <_UILabelContentLayer: 0x600000220260> (layer)
   |    | <UILabel: 0x7fd16fc04a60; frame = (164 225; 80 47); text = 'Qinz'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x600000088fc0>>
(lldb) 

注释:如果你在原生的XCode中,是敲不出这些命令的,上面只是演示了两个常见的LLDB插件命令的用法,更加高级的用法下面会详细说明。不过在这之前,我们要安装两个插件,接下来先讲解环境的配置。
2.1 chiselFacebook开源的一款LLDB插件,里面封装了很多好用的命令,当然这些命令都是基于苹果提供的api。chisel下载*

2.2 这里建议使用包管理工具Homebrew来安装,然后配置脚本路径,演示如下:

image.gif

2.3 然后在lldb窗口执行命令,演示如下:

image.gif

2.4 看到输出"command script import /usr/local/opt/chisel/libexec/fblldb.py"即代表安装成功,这里还会看到一个"command script import /opt/LLDB/lldb_commands/dslldb.py "路径,这是我们接下来要安装的第二个插件。

Executing commands in '/Users/Qinz/.lldbinit'.
command script import /usr/local/opt/chisel/libexec/fblldb.py
command script import /opt/LLDB/lldb_commands/dslldb.py
(lldb) 

2.5 这个插件的名称也叫LLDB,LLDB下载。我们先clone文件,我这里放置在opt文件夹下,你可以选择自己的文件目录放置,然后依次找到dslldb文件,在~/.initlldb文件中配置路径,演示如下:

image.gif

2.6 接下来依然在lldb窗口执行command source ~/.lldbinit命令。到此LLDB插件的配置环境完成,接下来我们讲解这些插件的实用命令。

lldb高级用法
taplog搭配flicker,让你快速找准控件,演示如下:

image.gif

taplog是点击控件,会打印控件的地址,大小及透明度等信息,我们拿到地址后执行flicker 0x7fd321e09710命令,此时控件会进行闪烁,这里动态图显示的闪烁效果明显。

showhide显示和隐藏控件,演示如下:

image.gif

vs命令方便动态查看控件的层级关系,演示如下:

image.gif

当我们执行vs命令后会进入动态调试阶段,会出现以下五个命令,每个命令我做了详细注释如下:

(lldb) vs 0x7fe73550a090
Use the following and (q) to quit.
(w) move to superview //移动到父视图
(s) move to first subview //移动到第一个子视图
(a) move to previous sibling  //移动上一个兄弟视图
(d) move to next sibling  //移动下一个兄弟视图
(p) print the hierarchy  //打印视图层级结构

pachtions直接打印对象调用者及方法,演示如下:

image.gif

border&unborder直接打印对象调用者及方法,演示如下:

image.gif

这里的-c即是color,-w即设置边框的宽度。通过这个命令我们可以很方便的查看边框的边缘的问题,而不需要每次重启运行。

pclass打印对象的继承关系,演示如下图:

image.gif

presponder命令打印响应链,演示如下图:

image.gif

caflush这个命令会重新渲染,即可以重新绘制界面, 相当于执行了 [CATransaction flush] 方法,演示如下:

image.gif

search搜索已经存在于栈中的控件及其子控件,演示如下:

image.gif

lookup搜索,可执行正则表达式。演示如下:

image.gif

上面的搜索会搜索所用镜像模块,我们重点看与我们工程名字相同的模块,即可查看哪些地方调用了这些方法。

pbundlepath打印app路径及pdocspath打印文档路径,演示如下:

image.gif

总结:上面详细讲解了LLDB常用命令及高级命令的用法,熟练掌握可大幅度提高Debug能力和开发效率。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容