调试工具Chisel-LLDB插件

Chisel-LLDB命令插件

   相信每一个人或多或少都在用LLDB来调试,好比po一个对象。LLDB的是很是强大的,且有内建的,完整的 Python 支持。今天咱们主要介绍一个 facebook 开源的 lldb 插件 Chisel。可让你的调试更Easy.python

1.安装Chisel

源码地址: Chiselgit

Chisel 使用 homebrew 来安装,若是你没有安装homebrew, 参考 homebrewgithub

1
2 
brew update brew install chisel

安装完成按照安装日志上的提示,在~/.lldbinit文件中添加一行,没有则新建。 提示相似以下:ide

1
2 3 
==> Caveats Add the following line to ~/.lldbinit to load chisel when Xcode launches:  command script import /usr/local/opt/chisel/libexec/fblldb.py

作好上面的步骤,而后重启Xcode就能够尝试下了。动画

2.内置命令

Chisel 为lldb提供了新增的便捷命令,是很是实用的命令ui

2.1 pviews

这个命令能够递归打印全部的view,并能标示层级,至关于 UIView 的私有辅助方法 [view recursiveDescription] 。 善用使用这个功能会让你在调试定位问题时省去不少麻烦。spa

使用示例:插件

1
2 3 4 5 6 7 8 9 
(lldb) pviews view <TestView: 0x18df8070; baseClass = UIControl; frame = (144 9; 126 167); layer = <CALayer: 0x18df8150>>  | <UIView: 0x18df81d0; frame = (0 0; 126 126); userInteractionEnabled = NO; layer = <CALayer: 0x18df8240>>  | <UIImageView: 0x18df8330; frame = (0 0; 126 126); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x18df83b0>>  | <UILabel: 0x18df8460; frame = (0 135; 126 14); text = 'haha'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x18df7fb0>>  | | <_UILabelContentLayer: 0x131a3d50> (layer)  | <UILabel: 0x18df8670; frame = (0 155; 126 12); text = 'hahaha'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x18df8730>>  | | <_UILabelContentLayer: 0x131bea10> (layer)  | <UIImageView: 0x18df88d0; frame = (0 9; 28 27); hidden = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x18df8ba0>>

2.2 pvc

这个命令也是递归打印层级,可是不是view,而是viewController。利用它咱们能够对viewController的结构一目了然。 其实苹果在IOS8也默默的添加了 UIViewController 的一个私有辅助方法 [UIViewController _printHierarchy] 一样的效果。debug

预览效果:设计

1
2 3 4 5 6 7 8 9 10 11 12 13 14 
(lldb) pvc <TabBarController: 0x13772fd0; view = <UILayoutContainerView; 0x151b3a30>; frame = (0, 0; 414, 736)>  | <UINavigationController: 0x1602b800; view = <UILayoutContainerView; 0x1b00aca0>; frame = (0, 0; 414, 736)>  | | <FirstViewController: 0x16029c00; view = <UIView; 0x1b01e1c0>; frame = (0, 0; 414, 736)>  | <UINavigationController: 0x138c5200; view = <UILayoutContainerView; 0x1316a080>; frame = (0, 0; 414, 736)>  | | <SecondViewController: 0x16030400; view = <UIView; 0x2094b370>; frame = (0, 0; 414, 736)>  | | | <SecondChildViewController: 0x15af6000; view = <UIView; 0x18d4e650>; frame = (0, 64; 414, 628)>  | <UINavigationController: 0x1383ca00; view = <UILayoutContainerView; 0x13180070>; frame = (0, 0; 414, 736)>  | | <ThirdViewController: 0x138ddc00; view = <UIView; 0x18df6650>; frame = (0, 0; 414, 736)>  | | | <ThirdChild1ViewController: 0x1393fe00; view = <UIView; 0x131ec000>; frame = (0, 0; 414, 672)>  | | | <ThirdChild2ViewController: 0x138dce00; view = <UIView; 0x204075a0>; frame = (414, 0; 414, 672)>  | | | <ThirdChild3ViewController: 0x138a8e00; view = <UIView; 0x20426250>; frame = (828, 0; 414, 672)>  | <UINavigationController: 0x160eca00; view = <UILayoutContainerView; 0x152f7d90>; frame = (0, 0; 414, 736)>  | | <FourViewController: 0x13157cc0; view not loaded>

是否是方便不少呢,并且还能够看到 viewController 是否已经 viewDidLoad .

2.3 visualize

这是个颇有意思的功能,它可让你使用Mac的预览打开一个 UIImage, CGImageRef, UIView, 或 CALayer。 这个功能或许能够帮咱们用来截图、用来定位一个view的具体内容。 可是在我试用了一下,发现暂时仍是只能在模拟器时使用,真机还不行。

使用简单:

1
(lldb) visualize imageView

2.4 fv & fvc

fv 和 fvc 这两个命令是用来经过类名搜索当前内存中存在的view和viewController实例的命令,支持正则搜索。

如:

1
2 3 4 5 6 7 8 9 
(lldb) fv scrollView 0x18d3b8c0 UIScrollView 0x137d0c50 UIScrollView 0x131b1580 UIScrollView 0x131b2070 UIScrollView (lldb) fvc Home 0x1393fe00 HomeFeedsViewController 0x138a8e00 HomeFeedsViewController (lldb)

2.5 show & hide

这两个命令用来显示和隐藏一个指定的 UIView . 你甚至不须要Continue Progress. 就能够看到效果。

2.6 mask/umask border/unborder

这两组命令用来标识一个view或layer的位置时用, mask用来在view上覆盖一个半透明的矩形, border能够给view添加边框。可是在我实际使用的过程当中mask老是会报错,估计是有bug, 那么mask/unmask 通常不要用好了,用border命令是同样的效果,反正两者的用途都是找到一个对应的view.

2.7 caflush

这个命令会从新渲染,便可以从新绘制界面, 至关于执行了 [CATransaction flush] 方法,要注意若是在动画过程当中执行这个命令,就直接渲染出动画结束的效果。

当你想在调试界面颜色、坐标之类的时候,能够直接在控制台修改属性,而后caflush就能够看到效果啦,是否是要比改代码,而后从新build省事多了呢。

例, 其中 $122 便是目标UIView:

1
2 3 4 
(lldb) p view (long) $122 = 140718754142192 (lldb) e (void)[$122 setBackgroundColor:[UIColor greenColor]] (lldb) caflush

2.8 bmessage

这个命令就是用来打断点用的了,虽然你们断点可能都喜欢在图形界面里面打,可是考虑一种状况:咱们想在 [MyViewController viewWillAppear:] 里面打断点,可是 MyViewController并无实现 viewWillAppear: 方法, 以往的做法可能就是在子类中实现下viewWillAppear:,而后打断点,而后rebuild。

那么幸亏有了 bmessage命令。咱们能够不用这样就能够打这个效果的断点: (lldb) bmessage -[MyViewController viewWillAppear:] 上面命令会在其父类的 viewWillAppear: 方法中打断点,并添加上了条件:[self isKindOfClass:[MyViewController class]]

3. 自定义命令

咱们也能够自定义插件,不过前提是要懂一些 python。 好比设计一个打印keyWindow的windowLevel的命令:

建立python脚本文件 /magical/commands/example.py :

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 
#!/usr/bin/python # Example file with custom commands, located at /magical/commands/example.py  import lldb import fblldbbase as fb  def lldbcommands():  return [ PrintKeyWindowLevel() ]  class PrintKeyWindowLevel(fb.FBCommand):  def name(self):  return 'pkeywinlevel'   def description(self):  return 'An incredibly contrived command that prints the window level of the key window.'   def run(self, arguments, options):  # It's a good habit to explicitly cast the type of all return  # values and arguments. LLDB can't always find them on its own.  lldb.debugger.HandleCommand('p (CGFloat)[(id)[(id)[UIApplication sharedApplication] keyWindow] windowLevel]') 

其中定义了PrintKeyWindowLevel的类,须要实现 name description run 方法来分别告诉名称、描述、和执行实体。

建立好脚本后,而后在前面安装时建立的 ~/.lldbinit文件中添加一行:

1
script fblldb.loadCommandsInDirectory('/magical/commands/') 

而后重启Xcode以后就可使用自定义的命令啦。

参考文档:http://blog.cnbluebox.com/blog/2015/03/05/chisel/

相关文章
相关标签/搜索