LLDB 是一个有着 REPL 的特性和 C++ ,Python 插件的开源调试器。LLDB 绑定在 Xcode 内部,存在于主窗口底部的控制台中。调试器允许你在程序运行的特定时暂停它,你可以查看变量的值,执行自定的指令,并且按照你所认为合适的步骤来操作程序的进展。
安装
1、brew update
2、brew install chisel
3、touch ~/.lldbinit,创建文件 .lldbinit,并将下面内容复制到文件中,保存退出。
command script import /usr/local/opt/chisel/libexec/fblldb.py
4、 重启xcode,插件即可生效
使用
Chisel是一个 facebook 开源的 lldb 插件,为lldb提供了新增的便捷命令,能够帮助快速 debug,是非常实用的命令。
为了跟踪demo UI与底层源码的关联,借助该插件中的强大的指令集可以帮助我们快速了解新接触的 demo。
首先,xcode 控制台输入”help” ,可以看到当前可用的一些指令集。如下图所示:
在平时的测试工作中,当拿到一个新的工程,面对demo 的各种控件,要查看当前控件对象的类的继承关系,可以通过pclass来查看,比如UIViewController处设置断点,呼出lldb控制台,然后再这里输入pclass这个命令,其中参数0x10400ba00为 tableView 对象的地址。如下图所示:
接下来,针对每个对象,使用pviews命令的输出中可以查看控件的属性,根据属性可以初步查看当前控件的位置及大小。如下图所示:
对于 demo 引用的到素材,visualize命令,可以使用mac下的预览app打开我们demo的图片UIImage, CGImageRef格式的图片,甚至view和layer的图片 ,如图所示:
当然,在测试 demo 的功能逻辑实现时是否正确时,简单的 UI层面还不够,需要深入到底层,了解每个对象的职责。pinternal可以查看一个控件类型的内部结构,包括自定义的控件的类型,比如查看控件 tableView 的内部结构,如下图所示:
除了需要对对象有一个纵向的认识外,要了解到对象之间的横向关系,使用presponder指令,如图五所示,列出了集成于tableView控件的消息传递链,方便我们查看消息是如何传递的。
这里只对常用的几个封装的命令进行了举例说明,其他常用的命令还有很多(详情见文末),都是使用python封装了一下函数然后调用的。凡是这些封装的命令,你都可以通过多个lldb命令打出来,Chisel插件帮我们集成了一些常用的指令集,如果你会使用python的话,那么你可以根据自己的使用习惯封装一些常用的lldb命令。
其他常用命令参考
一
在LLDB中,我们执行的最多的可能就是打印操作了,chisel专门为这类操作封装了一些打印命令。
1、pviews 递归打印所有的view,并能标示层级
2、pvc 递归打印层级viewController
3、ptv 打印屏幕中显示的tableView,主要是与pcells联合使用。如果有多个tableView,打印View层级中
最上面的一个。
4、pcells 打印tableView中当前可见的cell,如果有多个tableView,打印View层级中最上面的tableView
的可见cell。
5、pdata 对编码过的NSData进行解码打印,等效于调用-[NSString initWithData:encoding:]
6、po 以对象的方式打印结果
二
Find
1、fvc 根据类名搜索内存中与之匹配的 view
usage:Syntax: fvc [--name=classNameRegex] [--view=view]
--name/-n: string类型参数,根据viewController的Class名字查找viewController
--view/-v: UIView类型参数,根据viewController拥有的view查找viewController
Note:上面2个option不能同时使用,只能使用某一
2、fv 通过类名搜索当前内存中存在的viewController实例的命令,支持正则搜索。
3、taplog 将点击的view打印出来,这个命令对于查找哪个view非常有帮助。
usage:我们需要先将程序暂停,输入taplog,程序会自己运行,这时候点击你需要查看的view,控制台上就会显示出你刚刚点击的view相关信息。
Note:要查看的view必须能接收点击事件,也就是他的userInteractionEnabled必须为YES才能被找到,UILabel和UIImageView默认userInteractionEnabled为NO。
4、vs 在view层级中搜索view,并显示出来
Note:相比fv,vs主要用于显示view在屏幕上的位置
三
Display
1、caflush 一般我们用LLDB命令改变UI,UI并不会立即更新,我们需要使用caflush刷新界面
2、border 给View或者layer加上border
usage:
Syntax: border [--color=color] [--width=width]
<viewOrLayer>
--color/-c: 边框颜色,string类型
--width/-w: 边框宽度
<viewOrLayer>: 需要设置边框的view或者layer
3、mask 给view添加一个半透明的矩形mask,用来查看view的位置
usage:Syntax: mask [--color=color] [--alpha=alpha] <viewOrLayer>
--color/-c: mask的颜色,string类型
--alpha/-a: mask的透明度
<viewOrLayer>: 需要添加mask的view或者layer
4、show 显示一个view或者layer,相当于执行
view.hidden = NO
四
Preview
1、visualize 用预览App打开UIImage, CGImageRef, UIView, CALayer等对象
usage:
Syntax: visualize <target>
<target>: 需要预览的对象,id类型
五
Debug
1、bmessage 在类方法或实例方法中设置符号断点,而且不用担心层次结构中具体是哪个类实现了该方法。
usage:Syntax: bmessage <expression>
<expression>: 设置断点的方法名
2、wivar 在对象的实例上设置观察点(watchpoint)
usage:
Syntax: wivar <object> <ivarName>
<object>: 需要为成员变量设置watchpoint的对象。id类型
<ivarName>: 成员变量的名字,注意一般属性对应的成员变量带有_前缀
六
Autolayout
autolayout中有一种bug叫Ambiguous Layouts,意思是你设置的约束不足以确定view的位置或大小。比如你只设置了X轴的位置,没有设置Y轴的位置。
autolayout提供了专门判断和查找这类问题的方法:
1、hasAmbiguousLayout用于判断是否存在Ambiguous Layouts
2、_autolayoutTrace用于查找存在的Ambiguous Layouts
七
alamborder
即使有上述查找的方法,真正去做这个事儿也比较费时费力的, alamborder给存在Ambiguous Layouts的view加上border,方便查找哪些View存在问题。
usage:
Syntax: alamborder [--color=color] [--width=width]
1、--color/-c: border的颜色,参数为string类型,比如’red’, ‘green’, ‘magenta’等,不设置默认为红色。
--width/-w: border的宽度,参数为CGFloat类型,不设置默认宽度为2。
八
alamunborder
去掉alamborder设置的border。
usage:Syntax: alamunborder
e.g: 针对上面设置的border,在lldb控制台输入alamunborder即可去掉边框。
九
paltrace
打印某个View的autolayout详细信息,相当于调用_autolayoutTrace
usage:Syntax: paltrace <view>
其中<view>: 需要打印详细信息的view,不传参数默认为keyWindow。
eg: 查看一下keyWindow上有哪个view存在Ambiguous Layouts。
这篇文章是为了想你展示 LLDB 中Chisel插件的强大之处,鼓励我们避开繁琐的 NSlog, 尝试并探索在控制台使用命令的便捷性。
当然Chisel的命令很多,在这里只对常用的一些命令进行了总结,若有其他需求,请大家移至Chisel参考文档:github.com/facebook/ch…
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!