原文地址
iOS开发之LLDB常用调试技巧
用好了LLDB,让调试变得轻松愉快,本文会写出并示例讲解一些常用的指令,以让你爱上它~~
Debug的技巧有NSLog, LLDB, 但是NSLog效率低下,尽量少用NSLog。LLDB中强大的功能,完全能取代NSLog。
调试技巧:NSLog
NSLog比printf的效率要低几十倍,因为NSLog会向ASL写log,同时向Terminal写log,而且同时会出现在Console.app中。NSLog尽量不要在release中打开,在Debug中可以写一个宏:
#ifdef DEBUG
#define NSLog(FORMAT, ...) do {fprintf(stderr,"%s:%d\t%s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);} while(0)
#else
#define NSSLog(...)
#endif
调试技巧:LLDB
设置断点
- 在LLDB中设置断点,可以用breakpoint set命令(简写br set):
(lldb) br set -f WebpImageViewController.m -l 104
Breakpoint 10: where = DemoCollectOC`-[WebpImageViewController addTestButton] + 26 at WebpImageViewController.m:104, address = 0x000000010f8a859a
- 用b也可以创建断点,不过格式不同:
(lldb) b WebpImageViewController.m:97
Breakpoint 12: where = DemoCollectOC`-[WebpImageViewController testDict] + 588 at WebpImageViewController.m:97, address = 0x000000010f8a84ac
- b也可以在C语言函数上直接创建,断点停在函数的开始:
(lldb) b DecodeInto
Breakpoint 13: where = DemoCollectOC`DecodeInto + 30 at webp.c:453, address = 0x000000010f95977e
- 也可以在自定义函数、OC函数上设置断点:
(lldb) br set -F "-[UIView setBackgroundColor:]"
Breakpoint 14: where = UIKit`-[UIView(Rendering) setBackgroundColor:], address = 0x0000000112acae65
-
Condition & Action断点
在断点处右键编辑断点,Log Message可以在符合条件时断住并打印出自定义信息:
断点继续运行
thread return
打印当前线程堆栈:bt
打印所有线程中堆栈bt all
。
寻找栈地址对应代码位置: image
image lookup --address 0x000000000000
常用的po
po可以打印一个对象,p可以打印基本数据类型,po也可以打印出视图的层级关系:[self.view recursiveDescription]
,但打印不出frame,打印frame可以使用call来调用一句代码:call self.view.frame
。
LLDB更新UI
查看App整个层次:
(lldb) po [[[UIApplication sharedApplication] keyWindow] recursiveDescription]
<UIWindow: 0x7f96c7e0b080; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x608000244f80>; layer = <UIWindowLayer: 0x6080000288c0>>
| <UILayoutContainerView: 0x7f96c7e07b90; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x608000247d40>; layer = <CALayer: 0x608000029840>>
| | <UINavigationTransitionView: 0x7f96c7d0a590; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x600000025500>>
| | | <UIViewControllerWrapperView: 0x7f96c7e0bc30; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x608000029b00>>
| | | | <UIView: 0x7f96c7f0e6d0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x608000025460>>
| | | | | <_UILayoutGuide: 0x7f96c7f11040; frame = (0 0; 0 64); hidden = YES; layer = <CALayer: 0x6080000255c0>>
| | | | | <_UILayoutGuide: 0x7f96c7c01550; frame = (0 667; 0 0); hidden = YES; layer = <CALayer: 0x600000024980>>
| | | | | <UITableView: 0x7f96c801a000; frame = (0 0; 375 667);
在当前断点下,展示的为UITableView: 0x7f96c801a000,取到这个view:
(lldb) e id $myview = (id)0x7f96c801a000
改变颜色:
(lldb) e (void)[$myview setBackgroundColor:[UIColor redColor]]
我不想继续运行程序,还能看到颜色变化,也可以做到。渲染服务是一个另外的进程(backboardd),调试内容所在的进程被打断了,backdboardd也在运行着,可以用下面的命令也即时展示颜色改变:
(lldb) e (void)[CATransaction flush]
查找UIButton的target
如果你在LLDB中有一个button变量,可以新创建的,也可以是在UI中找到的,或者是断点处正在这个变量上,假设是断点在这个testButton变量上:
(lldb) po [testButton allTargets]
{(
<WebpImageViewController: 0x7fb2b670e2f0>
)}
(lldb) po [testButton actionsForTarget:(id)0x7fb2b670e2f0 forControlEvent:0]
<__NSArrayM 0x60800005c3b0>(
testButtonPressed:
)
观察实例变量变化
后面跟变量地址
(lldb) watchpoint set e -- 0x0000600000228d40
非重写方法符号断点
在子类中没有实现viewDidAppear方法,而是在父类中实现的,用breakpoint设置不可以,需要用Chisel中bmessage命令:
(lldb) bmessage -[WebpImageViewController viewDidAppear:]
Setting a breakpoint at -[UIViewController viewDidAppear:] with condition (void*)object_getClass((id)$rdi) == 0x000000010888aeb0
Breakpoint 2: where = UIKit`-[UIViewController viewDidAppear:], address = 0x000000010babd132