用Homebrew安装chisel
搞定Homebrew之后,你就可以用他来安装chisel了
12 | brew updatebrew install chisel |
官网的命令里有一个brew update
,是用来更新Homebrew版本的,如果你是新安装的Homebrew,可以省略掉这条命令
在~/.lldbinit
中添加命令
安装好之后,terminal中会出现这个东西
123 | ==>CaveatsAddthefollowinglineto~/.lldbinittoloadchiselwhenXcodelaunches: commandscriptimport/usr/local/opt/chisel/libexec/fblldb.py |
意思是需要把这个命令command script import /usr/local/opt/chisel/libexec/fblldb.py
加到~/.lldbinit
文件中
我们将命令其添加进去即可。如果你已经添加过一次了,不需要再次添加
12 | touch ~/.lldbinitecho "command script import /usr/local/opt/chisel/libexec/fblldb.py" >> ~/.lldbinit |
重启一下Xcode,安装完成
更新
如果你想更新chisel,只需要输入更新的命令即可
1 | brewupgradechisel |
命令
Autolayout
autolayout中有一种bug叫Ambiguous Layouts,意思是你设置的约束不足以确定view的位置或大小。比如你只设置了X轴的位置,没有设置Y轴的位置
autolayout提供了专门判断和查找这类问题的方法:
12 | hasAmbiguousLayout. Available for both iOS and OS X. Call this method on a misplaced view. It returns YES if the view’s frame is ambiguous. Otherwise, it returns NO._autolayoutTrace. Available as a private method in iOS. Call this method on a view. It returns a string with diagnostic information about the entire view hierarchy containing that view. Ambiguous views are labeled, and so are views that have translatesAutoresizingMaskIntoConstraints set to YES. |
-
hasAmbiguousLayout
用于判断是否存在Ambiguous Layouts
-
_autolayoutTrace
用于查找存在的Ambiguous Layouts
但是即使有查找的方法,真正去做这个事儿也比较费时费力的,这时候chisel给我们提供了更为方便的命令
alamborder
给存在Ambiguous Layouts
的view加上border,方便查找哪些View存在问题
语法:
1 | Syntax: alamborder[--color=color][--width=width] |
-
--color
/-c
: border的颜色,参数为string类型,比如’red’, ‘green’, ‘magenta’等,不设置默认为红色。 -
--width
/-w
: border的宽度,参数为CGFloat类型,不设置默认宽度为2。
e.g: 假设我们写了这么一段代码,可以明显看出,我们没有设置X轴的位置。
123456 | UIView *subview = [UIView new];[self.view addSubview:subview];[subview mas_makeConstraints:^(MASConstraintMaker *make) { make.top.offset(100); make.size.equalTo(@100);}]; |
运行代码之后,在LLDB控制台输入alamborder
1 | (lldb)alamborder |
所有带有Ambiguous Layouts
的view立即会被渲染上红色border
可以看到,subview的边框已经变为红色,另外只要有一个View存在Ambiguous Layouts
,UIWindow的边框也会变为红色,这就有效的避免了宽度或者高度为0的Ambiguous Layouts
不宜察觉的缺陷。
alamunborder
将alamborder
设置的border去掉.
语法:
1 | Syntax: alamunborder |
e.g: 刚刚设置的border,在lldb控制台输入alamunborder
即可去掉边框
1 | (lldb)alamborder |
paltrace
打印某个View的autolayout详细信息,相当于调用_autolayoutTrace
语法:
1 | Syntax: paltrace <view> |
-
<view>
: 需要打印详细信息的view,不传参数默认为keyWindow
e.g: 查看一下keyWindow上有哪个view存在Ambiguous Layouts
1234567891011 | (lldb)paltrace•UIWindow:0x7ff450d2fb50-AMBIGUOUSLAYOUT| •UIView:0x7ff450e14430| | *_UILayoutGuide:0x7ff450d30e90| | *_UILayoutGuide:0x7ff450d31230| | *UIView:0x7ff450d32870-AMBIGUOUSLAYOUTfor UIView:0x7ff450d32870.minX{id:46} Legend: *-islaidoutwithautolayout +-islaidoutmanually,butisrepresentedinthelayoutenginebecausetranslatesAutoresizingMaskIntoConstraints=YES •-layoutenginehost |
我们可以看到,UIView:0x7ff450d32870
存在Ambiguous Layouts
,原因是缺少minX
。也就是没有设置X轴的位置
在LLDB中,我们执行的最多的可能就是打印操作了,chisel专门为这类操作封装了一些打印命令
pviews
循环打印view层级,正常情况下等效于调用recursiveDescription
命令
123 | // 下面2条命令等效(lldb) po [self.view recursiveDescription](lldb) pviews self.view |
语法:
1 | pviews[--up][--depth=depth]<aView> |
-
--up
/-u
: 以view为起始位置,向上打印,直到打印到window层 -
--depth
/-d
: 传入int类型,表示打印的层数,0表示没有限制
e.g: 打印一下self.view层级
1234567 | (lldb) pviews self.view<UIView: 0x7fee7ae1fa60; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fee7ae1d3c0>> | <UIButton: 0x7fee7ae1dd90; frame = (54 244; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fee7ae1e300>> | <UIView: 0x7fee7ae1f2e0; frame = (35 312; 240 128); autoresize = RM+BM; layer = <CALayer: 0x7fee7ae1f660>> | <_UILayoutGuide: 0x7fee7ae1fc20; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fee7ae20030>> | <_UILayoutGuide: 0x7fee7ae20b30; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fee7ae1d100>> | <UILabel: 0x7fee7ae1d3f0; frame = (0.4 150; 58.25 20.5); text = 'aaa'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fee7ae1bb30>> |
pvc
循环打印viewController的层级
语法:
1 | Syntax: pvc<aViewController> |
<aViewController>
: 表示要打印的viewController,不传参数默认viewController为当前的VC
e.g: 打印一下当前VC
1234 | (lldb) pvc<UINavigationController 0x7fce1a03d800>, state: appeared, view: <UILayoutContainerView 0x7fce19500c00> | <ViewController 0x7fce1c03a1d0>, state: disappeared, view: <UIView 0x7fce19517b40> not in the window | <TableViewController 0x7fce1951f7b0>, state: appeared, view: <UIView 0x7fce1c053e60> |
pclass
循环打印class的继承关系
语法:
1 | Syntax: pclass<object> |
<object>
: 要打印继承关系的对象
e.g: 打印一个View对象的继承关系
1234 | (lldb) pclass [UIView new]UIView | UIResponder | | NSObject |
presponder
打印响应链
语法:
1 | Syntax: presponder<startResponder> |
<startResponder>
: UIResponder对象,响应链开始位置
e.g: 打印一个tableView的响应链
1234 | (lldb) presponder tableView<UITableView: 0x7fde54810e00; frame = (0 0; 0 0); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x7fde52519ac0>; layer = <CALayer: 0x7fde5253b4c0>; contentOffset: {0, 0}; contentSize: {0, 220}> | <UIView: 0x7fde5255c710; frame = (0 0; 600 600); autoresize = W+H; layer = <CALayer: 0x7fde5253b300>> | | <TableViewController: 0x7fde52491310> |
ptv
打印屏幕中显示的tableView,主要是与pcells
联合使用。如果有多个tableView,打印View层级中最上面的一个
语法:
1 | Syntax: ptv |
e.g: 看看当前最上面是哪个tableView
12 | (lldb) ptv<UITableView: 0x7fde52811800; frame = (0 0; 414 736); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7fde526418d0>; layer = <CALayer: 0x7fde5260adc0>; contentOffset: {0, -64}; contentSize: {414, 176}> |
pcells
打印tableView中当前可见的cell,如果有多个tableView,打印View层级中最上面的tableView的可见cell
语法:
1 | Syntax: pcells |
e.g: 看看当前可见的cell有哪些
1234567 | (lldb) pcells<__NSArrayI 0x7fde52565a00>(<UITableViewCell: 0x7fde52551180; frame = (0 0; 414 44); text = 'BasicViewController'; autoresize = W; layer = <CALayer: 0x7fde52537140>>,<UITableViewCell: 0x7fde5255bea0; frame = (0 44; 414 44); text = 'DateViewController'; autoresize = W; layer = <CALayer: 0x7fde5255b1a0>>,<UITableViewCell: 0x7fde5255e2d0; frame = (0 88; 414 44); text = 'PPTViewController'; autoresize = W; layer = <CALayer: 0x7fde5255e270>>,<UITableViewCell: 0x7fde5255fce0; frame = (0 132; 414 44); text = 'TableViewController'; autoresize = W; layer = <CALayer: 0x7fde5255fa90>>) |
pinternals
打印一个对象内部的成员变量,这个方法我一般用来看model属性
语法:
1 | Syntax: pinternals<object> |
-
<object>
: 需要打印内部成员变量的对象
e.g: 我们来看看一个model
内部属性的值
123456789 | (lldb) pinternals model(Model) $5 = { _name = 0x000000010dd1c0a0 @"老鼠爱大米" _URL = nil _array = nil _dictionary = nil _string = nil _model = nil} |
pdata
对编码过的NSData进行解码打印,等效于调用-[NSString initWithData:encoding:]
语法:
1 | Syntax: pdata[--encoding=encoding]<data> |
-
<data>
: 需要打印的data,NSData类型 -
--encoding
/-e
: 编码类型,如果缺省默认为utf8,主要支持的类型有:
123456789101112131415 | - ascii,- utf8,- utf16, unicode,- utf16l (Little endian),- utf16b (Big endian),- utf32,- utf32l (Little endian),- utf32b (Big endian),- latin1, iso88591 (88591),- latin2, iso88592 (88592),- cp1251 (1251),- cp1252 (1252),- cp1253 (1253),- cp1254 (1254),- cp1250 (1250), |
e.g: 将一个utf8的NSData打印
12 | (lldb)pdata-e=utf8data老鼠爱大米 |
pkp
通过-valueForKeyPath:
打印key path
对应的值。
语法:
1 | Syntax: pkp <keypath> |
-
<keypath>
: 需要打印的路径,如self.view
说明:以前打印属性一般都用po obj.xxx
,现在我想用pkp obj.xxx
是一个更好的选择了,因为po obj.xxx
是调用getter方法,如果没有getter方法就无法打印了。pkp obj.xxx
不仅会调用getter方法,没有getter方法还会去查找成员变量
e.g: 打印一下self.view
12 | (lldb)pkpself.view<UIView:0x7fd1da52d5d0;frame=(00;375667);autoresize=W+H;layer=<CALayer:0x7fd1da52d740>> |
pivar
打印对象成员变量
语法:
1 | Syntax: pivar <object> <ivarName> |
-
<object>
: id类型,要打印成员变量的对象 -
<ivarName>
: 成员变量的名称,注意:如果是属性,对应成员变量的名字默认有_
前缀.
说明:个人觉得这个方法有点鸡肋,pinternals
一下子可以打印出所有的成员变量,用起来更方便,如果你只想打印某一个成员变量,用pkp
应该更爽
e.g: 继续打印self.view
12 | (lldb)pivarself_view<UIView:0x7fd1da52d5d0;frame=(00;375667);autoresize=W+H;layer=<CALayer:0x7fd1da52d740>> |
pca
从渲染服务器的角度来打印layer tree
,命令的完整名字是PrintCoreAnimationTree
,相当于调用po [NSString stringWithCString:(char *)CARenderServerGetInfo(0, 2, 0)]
语法:
1 | Syntax: pca |
说明:这个命令我也没用过,可能在某些情况下会有用处
e.g: 试一下pca
123456789101112131415161718192021222324 | (lldb)pca==context956ecbbf;level0;pid28092[/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/CoreServices/SpringBoard.app/SpringBoard](secure)attime34552.989286== (layer[3756670][00375667][0.50.50] (transform[2-000;0200;0010;0001]) (rasterizationScale2) (sublayers(array (layer[187.5333.50][00375667][0.50.50] (masksToBoundstrue) (sublayers(array (layer[187.5333.50][00375667][0.50.50] (backgroundColor#000000ff) (sublayers(array (layer[187.5333.50][00375667][0.50.50] (sublayers(array (layer[187.5333.50][00375667][0.50.50] (sublayers(array (layer[187.5333.50][00375667][0.50.50] (sublayers(array (layer[187.5333.50][00375667][0.50.50] (masksToBoundstrue) (edgeAntialiasingMask0) (subclass(layer-hostadc504e5 ....东西太多,省略部分内容......... |
panim
显示是否正在执行动画,相当于调用p (BOOL)[UIView _isInAnimationBlock]
语法:
1 | Syntax: panim |
说明:这个命令也并不常用
e.g: 在动画中,我们打印一下:
12 | (lldb)panim(BOOL)$0=YES |
Find
debug的时候,我们经常需要查找一些东西,比如View,viewController等。
fvc
根据viewController的Class名字查找VC
语法:
1 | Syntax: fvc [--name=classNameRegex] [--view=view] |
-
--name
/-n
: string类型参数,根据viewController的Class名字查找viewController -
--view
/-v
: UIView类型参数,根据viewController拥有的view查找viewController
说明:上面2个option不能同时使用,只能使用某一个
e.g: 我们先根据名字查找一下VC
12 | (lldb)fvc--name=viewcontroller0x7fd01a90f310ViewController |
e.g: 如果我们知道VC的view地址,也可以根据view来查找VC
123 | (lldb) fvc --view=0x7fd0194194d0Found the owning view controller.<ViewController: 0x7fd01a90f310> |
fv
根据view的class名字查找view
语法:
1 | Syntax: fv<classNameRegex> |
-
<classNameRegex>
: view的class名称
e.g: 查找一下屏幕上的UILabel
12 | (lldb) fv uilabel0x7fd01a91dc10 UILabel |
taplog
将点击的view打印出来,这个命令对于查找哪个view非常有帮助
语法:
1 | Syntax: taplog |
说明:要查看的view必须能接收点击事件,也就是他的userInteractionEnabled
必须为YES才能被找到,UILabel和UIImageView默认userInteractionEnabled
为NO。
用法:我们需要先将程序暂停,输入taplog
,程序会自己运行,这时候点击你需要查看的view,控制台上就会显示出你刚刚点击的view相关信息
e.g: 我们先将程序暂停,输入taplog
12 | (lldb) taplogProcess 28421 resuming |
程序会自己运行,我们再点击一个UIButton:
1 | <UIButton:0x7fe6785284e0;frame=(54244;4630);opaque=NO;autoresize=RM+BM;layer=<CALayer:0x7fe678528a50>> |
flicker
将view闪烁一下,以便于查找view的位置
语法:
1 | Syntax: flicker <viewOrLayer> |
-
<viewOrLayer>
需要闪烁的view或者layer
e.g: 我们来看看self.subView的位置
1 | (lldb)flickerself.subView |
vs
在view层级中搜索view,并显示出来
语法:
1 | Syntax: vs <view> |
-
<view>
:要查找的view
说明:相比fv
,vs
主要用于显示view在屏幕上的位置,2个命令可以配合使用
e.g: 假设我们要找屏幕上的一个view
首先用fv
查找UIView
类型的view
123 | (lldb)fvuiview0x7fbcf37228d0UIView0x7fbcf3725e90UIView |
然后看看这2个view到底哪个是我们想要找的view
12345678910 | (lldb) vs 0x7fbcf3725e90 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 <UIView: 0x7fbcf3725e90; frame = (0 100; 100 100); layer = <CALayer: 0x7fbcf3712a40>> |
输入命令后他会帮我们在屏幕上用粉红色标志出来vs
的view
控制台中vs
的view也有相应log。并且还提示有6种子命令:
-
w
: 移动到superview -
s
: 移动到第一个subview -
a
: 移动到前面的同级view -
d
: 移动到后面的同级view -
p
: 打印出层级 -
q
: 退出
如果这个不是我们要找的view,可以使用w
,s
,a
,d
,p
命令继续查找
Display
debug的时候,可能有一小半的工作是跟UI打交道,关于UI显示上的东西,也有几个命令
caflush
刷新UI界面。一般我们用LLDB命令改变UI,UI并不会立即更新,我们需要使用caflush
刷新界面
语法:
1 | Syntax: caflush |
e.g: 我们用命令将label的背景色改为红色
1234 | (lldb) fv uilabel0x7fb3919189d0 UILabel(lldb) e [((UILabel*)0x7fb3919189d0) setBackgroundColor:[UIColor redColor]](lldb) caflush |
border
给View或者layer加上border
语法:
1 | Syntax: border[--color=color][--width=width]<viewOrLayer> |
-
--color
/-c
: 边框颜色,string类型,比如:’red’, ‘green’ ‘magenta’等,不设置默认为红色 -
--width
/-w
: 边框宽度,不设置默认为2 -
<viewOrLayer>
: 需要设置边框的view或者layer
e.g: 给刚刚的label加上边框
123 | (lldb) fv uilabel0x7fe713901f10 UILabel(lldb) border 0x7fe713901f10 |
unborder
去掉view或者layer的border
语法:
1 | Syntax: unborder<viewOrLayer> |
e.g: 将刚刚加上的border去掉
1 | (lldb) unborder 0x7fe713901f10 |
mask
给view添加一个半透明的矩形mask,用来查看view的位置
语法:
1 | Syntax: mask[--color=color][--alpha=alpha]<viewOrLayer> |
-
--color
/-c
: mask的颜色,string类型,比如:’red’, ‘green’,’magenta’等,不设置默认为红色 -
--alpha
/-a
: mask的透明度,不设置默认为0.5 -
<viewOrLayer>
: 需要添加mask的view或者layer
e.g: 假如label是隐藏的,我们给他添加一个mask,看看他的位置在哪儿
123 | (lldb) fv uilabel0x7fe713901f10 UILabel(lldb) mask 0x7fe713901f10 |
unmask
将添加的mask去掉
语法:
1 | Syntax: unmask<viewOrLayer> |
-
<viewOrLayer>
: 需要去掉mask的view或者layer
e.g: 我们将刚刚添加的mask去掉
1 | (lldb) unmask 0x7fe713901f10 |
使用命令之后,我们可以看到什么都没有了,因为label是hidden的
show
显示一个view或者layer,相当于执行view.hidden = NO
语法:
1 | Syntax: show<viewOrLayer> |
-
<viewOrLayer>
: 需要显示的view或者layer
e.g: 将刚刚的label显示出来
1 | (lldb) show 0x7fe713901f10 |
hide
隐藏一个view或者layer,相当于执行view.hidden = YES
语法:
1 | Syntax: hide<viewOrLayer> |
-
<viewOrLayer>
: 需要隐藏的view或者layer
e.g: 又把label隐藏
1 | (lldb) hide 0x7fe713901f10 |
可以看到label位置什么都没有了
slowanim
减慢动画的速度
语法:
1 | Syntax: slowanim<speed> |
-
<speed>
: 动画的速度,速度越大,动画越快。1表示原始速度。不传参数默认为0.1
e.g: 原始动画我们设置为1s
123 | [UIView animateWithDuration:1 animations:^{ self.subView.frame = frame;}]; |
暂停程序,将动画放慢5倍
1 | (lldb)slowanim0.2 |
我们可以看到动画变慢了:
unslowanim
取消slowanim
效果,将动画速度变为正常
语法:
1 | Syntax: unslowanim |
e.g: 我们将刚刚的slowanim
效果取消
1 | (lldb)unslowanim |
Preview
预览功能,帮助我们用命令查看一个view或者图片的真正样子
visualize
用预览App打开UIImage, CGImageRef, UIView, CALayer等对象
语法:
1 | Syntax: visualize <target> |
-
<target>
: 需要预览的对象,id类型
e.g: 我们来看看某个image的样子
1 | (lldb)visualizeimage |
Debug
LLDB主要用于Debug,chisel怎么可能缺少debug相关命令呢?
wivar
为对象的成员变量设置watchpoint
,更多watchpoint
相关知识请阅读<小笨狼与LLDB的故事>
语法:
1 | Syntax: wivar <object> <ivarName> |
-
<object>
: 需要为成员变量设置watchpoint
的对象。id类型 -
<ivarName>
: 成员变量的名字,注意一般属性对应的成员变量带有_
前缀
e.g: 为self.subView设置watchpoint
12 | (lldb)wivarself_subViewRemembertodeletethewatchpointusing: watchpointdelete1 |
这时候,_subView值改变就会中断程序
bmessage
根据方法名设置断点
语法:
1 | Syntax: bmessage <expression> |
-
<expression>
: 设置断点的方法名,如:-[MyView setFrame:]
,+[MyView awesomeClassMethod]
,-[0xabcd1234 setFrame:]
等
说明:一般设置断点,如果这个方法本类没有实现,是父类实现的,断点是无效的。bmessage
有效避免了这种缺陷,即使本类没有实现,也能设置上断点
e.g: 给self中的btnAction:
方法设置一个断点
123 | (lldb)bmessage-[selfbtnAction:]Settingabreakpointat-[ViewControllerbtnAction:] withcondition(void*)(id)$rdi==0x00007ff2485311e0Breakpoint4: where=TLLDB`-[ViewControllerbtnAction:] atViewController.m:42,address=0x000000010c4bb620 |
binside
通过一个相对地址,给framework(library)设置断点
语法:
1 | Syntax: binside <address> |
-
<address>
: framework的相对地址
pinvocation
打印方法调用堆栈,仅支持x86
语法:
1 | Syntax: pinvocation[--all] |
-
--all
/-a
: 表示打印所有堆栈,不设置默认只打印当前堆栈
说明:与bt
命令类似,不过信息比bt
打印得更详细,遗憾的是只能支持x86
e.g: 打印一下当前堆栈
1234 | (lldb) pinvocationframe #0: 0x000962aa TMasonry`-[ViewController viewDidLoad](self=0x7bf2d9c0, _cmd="viewDidLoad") + 234 at ViewController.m:28NSInvocation: 0x7bf433e0self: 0x7bf2d9c0 |
打印所有堆栈:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 | (lldb)pinvocation-aframe#0: 0x000962aa TMasonry`-[ViewController viewDidLoad](self=0x7bf2d9c0, _cmd="viewDidLoad") + 234 at ViewController.m:28NSInvocation:0x7d2bb050self:0x7bf2d9c0---------------------------------frame#1: 0x008062ae UIKit`-[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 44NSInvocation:0x7be18a50self:0x7bf2d9c0---------------------------------frame#2: 0x0080adce UIKit`-[UIViewController loadViewIfRequired] + 1384NSInvocation:0x7bf0cc40self:0x7bf2d9c0---------------------------------frame#3: 0x008569f9 UIKit`-[UINavigationController _layoutViewController:] + 52NSInvocation:0x7d340c90self:0x7c89ee00 Argument:0xbff69108,addressof@}0x7bf2d9c0---------------------------------frame#4: 0x008572b1 UIKit`-[UINavigationController _updateScrollViewFromViewController:toViewController:] + 421NSInvocation:0x7d340cc0self:0x7c89ee00 2Arguments:0xbff69158,addressof@}0x00xbff6915c,addressof@}0x7bf2d9c0---------------------------------frame#5: 0x00857458 UIKit`-[UINavigationController _startTransition:fromViewController:toViewController:] + 145NSInvocation:0x7bf24870self:0x7c89ee00 3Arguments:0xbff69298,addressofi}00xbff6929c,addressof@}0x00xbff692a0,addressof@}0x7bf2d9c0---------------------------------frame#6: 0x00858854 UIKit`-[UINavigationController _startDeferredTransitionIfNeeded:] + 1038NSInvocation:0x7bf16b50self:0x7c89ee00 Argument:0xbff692f8,addressof@}0x0---------------------------------frame#7: 0x00859ada UIKit`-[UINavigationController __viewWillLayoutSubviews] + 68NSInvocation:0x7be18930self:0x7c89ee00---------------------------------frame#8: 0x00a35c4a UIKit`-[UILayoutContainerView layoutSubviews] + 252NSInvocation:0x7bf26ab0self:0x7bf40d40---------------------------------frame#9: 0x0070b008 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 810NSInvocation:0x7bf25da0self:0x7bf40d40 Argument:0xbff693b8,addressof@}0x7bf40f80---------------------------------frame#10: 0x01b23059 libobjc.A.dylib`-[NSObject performSelector:withObject:] + 70NSInvocation:0x7d2bb6c0self:0x7bf40d40 2Arguments:0xbff693d8,addressof:}layoutSublayersOfLayer:0xbff693dc,addressof@}0x7bf40f80---------------------------------frame#11: 0x0496b80a QuartzCore`-[CALayer layoutSublayers] + 144NSInvocation:0x7bf134c0self:0x7bf40f80---------------------------------frame#12: 0x0495f4ee QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 388---------------------------------frame#13: 0x0495f352 QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 26---------------------------------frame#14: 0x04951e8b QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 317---------------------------------frame#15: 0x04985e03 QuartzCore`CA::Transaction::commit() + 561---------------------------------frame#16: 0x049866c4 QuartzCore`CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 92---------------------------------frame#17: 0x01f66ffe CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30---------------------------------frame#18: 0x01f66f5e CoreFoundation`__CFRunLoopDoObservers + 398---------------------------------frame#19: 0x01f5c108 CoreFoundation`CFRunLoopRunSpecific + 504---------------------------------frame#20: 0x01f5befb CoreFoundation`CFRunLoopRunInMode + 123---------------------------------frame#21: 0x00639206 UIKit`-[UIApplication _run] + 540NSInvocation:0x7d21fc00self:0x7d30bfe0---------------------------------frame#22: 0x0063ebfa UIKit`UIApplicationMain + 160---------------------------------frame#23: 0x00096a0a TMasonry`main(argc=1, argv=0xbff6a898) + 138 at main.m:14---------------------------------frame#24: 0x031caa21 libdyld.dylib`start + 1--------------------------------- |
Accessibility
这个模块的命令主要利用了UIAccessibility
相关特性,需要开启Accessibility功能才能使用,UIAccessibility
详细资料可以阅读UIAccessibility
fa11y
根据view的accessibilityLabel查找view
语法:
1 | Syntax: fa11y <labelRegex> |
-
<labelRegex>
: 需要匹配的text
说明:UILabel,UIButton的accessibilityLabel
等于title
e.g: 我们根据显示的文案,查找相应的控件
12 | (lldb)fa11y妈妈(UILabel0x176b5bd0)妈妈叫你回家吃饭了 |
pa11y
打印view层级中所有的accessibilityLabel
语法:
1 | Syntax: pa11y <aView> |
-
<aView>
: 需要打印层级的View,UIView类型
e.g: 我们打印一下self.view层级中所有的accessibilityLabel
1234 | (lldb)pa11yself.viewUIViewself.view |(UIButton0x176b4600)Button |(UILabel0x176b5bd0)妈妈叫你回家吃饭了 |
End
chisel的命令就介绍到这里,东西挺多的,没必要全部都记住,我把这个写出来就打算当做一个文档,以后记不起哪个命令就查一下自己的博客。
不过chisel确实是个好东西,工欲善其事,必先利其器。要想要方便的调bug,chisel绝对值得你拥有
原文链接: http://ios.jobbole.com/83589/
GitHub: https://github.com/gkassabli/chisel