断点(转载)
http://mp.weixin.qq.com/s?__biz=MzA4ODk0NjY4NA==&mid=230272985&idx=1&sn=045c98bfb2d8dd1ecf7a732189935081&scene=0#rd
编码不能没调试,调试不能没断点(Break Point)。XCode的断点功能也是越来越强大。
基本断点
如下图,这种是最常用的断点,也是最容易设置。左键点击一下就可以设置。
编辑断点
断点是可以编辑的。
断点有下面几个属性可以设置:
·Condition
·Ignore
·Action
·Options
Condition
这里可以输入条件表达式,满足条件的时候断点就会生效。例如上面输入a == 50。这个是非常有用的设置,特别在循环体内调试的时候,用着真的是爽。
Ingore
在这里可以设置忽略断点次数。
Action
Action是这里最复杂的,最强大的功能了。Action有6中类型。如下图
1. AppleScript
2. Capture GPU Frame
3. Debugger Command
4. Log Message
5. Shell Command
6. Sound
常用的就是Log Message和Debugger Command 。
Log Message
在这里填写的东西可以打印到控制台。例如我做了如下设置
%B会打印断点的名字,%H会打印断点的调用次数,@@中间可以输入表达式。 上面的设置在控制台的输出如下:
...
-application:didFinishLaunchingWithOptions: 92 20
2015-07-28 22:19:21.905 Test[981:38016] 91
-application:didFinishLaunchingWithOptions: 93 20
-application:didFinishLaunchingWithOptions: 94 20
-application:didFinishLaunchingWithOptions: 95 20
2015-07-28 22:19:21.913 Test[981:38016] 92
2015-07-28 22:19:21.921 Test[981:38016] 93
2015-07-28 22:19:21.929 Test[981:38016] 94
-application:didFinishLaunchingWithOptions: 96 20
2015-07-28 22:19:21.937 Test[981:38016] 95
-application:didFinishLaunchingWithOptions: 97 20
2015-07-28 22:19:21.944 Test[981:38016] 96
-application:didFinishLaunchingWithOptions: 98 20
2015-07-28 22:19:21.952 Test[981:38016] 97
-application:didFinishLaunchingWithOptions: 99 20
2015-07-28 22:19:21.959 Test[981:38016] 98
-application:didFinishLaunchingWithOptions: 100 20
2015-07-28 22:19:21.967 Test[981:38016] 99
Debugger Command
这里可以输入调试命令,也就是po(打印对象信息),bt(打印函数栈),expression(表达式)这些调试命令。看图就明白了:
控制台输出如下:
* thread #1: tid = 0xb7db, 0x0000000101d0eb11 Test`-[AppDelegate application:didFinishLaunchingWithOptions:](self=0x00007fc923400570, _cmd=0x00000001033f3123, application=0x00007fc92360b1d0, launchOptions=0x0000000000000000) + 97 at AppDelegate.m:20, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000101d0eb11 Test`-[AppDelegate application:didFinishLaunchingWithOptions:](self=0x00007fc923400570, _cmd=0x00000001033f3123, application=0x00007fc92360b1d0, launchOptions=0x0000000000000000) + 97 at AppDelegate.m:20
frame #1: 0x0000000102c0d748 UIKit`-[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 240
frame #2: 0x0000000102c0e357 UIKit`-[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2540
frame #3: 0x0000000102c1119e UIKit`-[UIApplication _runWithMainScene:transitionContext:completion:] + 1349
frame #4: 0x0000000102c10095 UIKit`-[UIApplication workspaceDidEndTransaction:] + 179
frame #5: 0x0000000107d3c5e5 FrontBoardServices`__31-[FBSSerialQueue performAsync:]_block_invoke_2 + 21
frame #6: 0x00000001024da41c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
frame #7: 0x00000001024d0165 CoreFoundation`__CFRunLoopDoBlocks + 341
frame #8: 0x00000001024cff25 CoreFoundation`__CFRunLoopRun + 2389
frame #9: 0x00000001024cf366 CoreFoundation`CFRunLoopRunSpecific + 470
frame #10: 0x0000000102c0fb02 UIKit`-[UIApplication _run] + 413
frame #11: 0x0000000102c128c0 UIKit`UIApplicationMain + 1282
frame #12: 0x0000000101d0edbf Test`main(argc=1, argv=0x00007fff5def13a8) + 111 at main.m:14
frame #13: 0x0000000104dbd145 libdyld.dylib`start + 1
frame #14: 0x0000000104dbd145 libdyld.dylib`start + 1
(int) $2 = 98
2015-07-28 22:36:54.654 Test[1150:47067] 98
2015-07-28 22:36:54.670 Test[1150:47067] 99
Options
勾选Automatically continue after evaluating actions之后程序会在断点产生后继续运行。这个属性是相当有用的,可以输入调试信息至于不暂停程序。
出了上面的基本断点外,XCode还提供了下面四种断点,需要点击断点面板左下角的+号添加。
·Exception Breakpoint(全局断点)
·OpenGL ES Error Breakpoint
·Symbolic Breakpoint
·Test Failure Breakpoint
Exception Breakpoint
Exception Breakpoint是一个非常有用的断点项。正如名字所示,当程序抛出异常的时候就回产生断点。通常程序崩溃会停在崩溃的地方,但有时候并不能准确停在引起异常的地方。比如数组越界!比如我下图所示,会引起数组越界访问。
程序运行的时候就会崩溃。但是崩溃停在了main函数里面,就算看了栈信息也不能马上定位到到底是那个数组越界访问了。为什么崩溃不能停在数组越界哪里?这是因为数组越界访问不一定会导致程序崩溃的,数组越界访问会导致异常抛出,而抛出的异常没有得到处理才会导致程序崩溃。因此最后会导致崩溃停在CoreFoundation框架里面。这个时候就需要设置Exception Breakpoint产生断点来定位错误了。
OpenGL ES Error Breakpoint
这个主要是OpenGL ES的断点调试,这个个人没用到过。
Symbolic Breakpoint
Symbolic Breakpoint,符号断点,真的是调试神器啊。当程序运行到特定符号的时候就会产生断点。通过这种方式添加断点,就不需要在源文件中添加,也不需要知道断点设置在文件的第几行。如图:
比普通断点多了两个属性Symbol和Module。
Symbol
Symbol的内容,可以有如下几种:
1. 方法名称:会对所有具有此方法名称的类方法生效。例如 initWithFrame: 。
2. 特定类的方法:OC类和C++类都适用,例如 ,[UIView initWithFrame:]或者 Shap::draw()。
3. 函数名称。例如普通C函数。
通过设置Symbol来调试,好用根本停不下来,想怎么断点就怎么断点。
Test Failure Breakpoint
这个类型的断点会在test assertion 失败的时候暂停程序的执行。
转载自 http://www.xuebuyuan.com/1447528.html
iOS 调试 crash breakpoint EXC_BAD_ACCESS SIGABRT
在调试程序的时候,总是碰到crash的bug,而且一追踪就是一些汇编的代码,让人特别疑惑。
一般情况下可以通过增加两天断点来解决此问题,方法介绍如下:
基本上有错误分为以下几种类型:
signal(SIGABRT, MySignalHandler);
signal(SIGILL, MySignalHandler);
signal(SIGSEGV, MySignalHandler);
signal(SIGFPE, MySignalHandler);
signal(SIGBUS, MySignalHandler);
signal(SIGPIPE, MySignalHandler);
SIGABRT和EXC_BAD_ACCESS较为特殊,算是比较好跟进。
SIGABRT是系统报错,在memery warning之后,系统会把程序强制退出,报的就是这个错误。
EXC_BAD_ACCESS 大多数时候是内存提前释放而引起的问题,或者访问的方法不存在引起的。
1. Xcode内置GDB,可以使用GDB调试,调试命令:
1.1 po 命令:为 print object 的缩写,显示对象的文本描述
(lldb) po [$eax class]:输出异常对象的地址
(lldb) po [$eax name]:输出这个异常的名字
(lldb) po [$eax reason]:这个将会输出错误消息:
(lldb) “po $eax”:对这个对象调用“description”方法和打印出来
“$eax”是cup的一个寄存器。在一个异常的情况下,这个寄存器将会包含一个异常对象的指针。注意:$eax只会在模拟器里面工作,假如你在设备上调试,你将需要使用”$r0″寄存器
1.2 print 命令:有点类似于格式化输出,可以输出对象的不同信息
比如:print (char*)[[dic description] cString]、(lldb) print (int)[label retainCount]
1.3 info 命令:我们可以查看内存地址所在信息
1.4 info line *内存地址:可以获取内存地址所在的代码行相关信息
1.5 show 命令:显示 GDB 相关的信息。如:show version 显示GDB版本信息
1.6 bt: 显示当前进程的函数调用栈的情况;"up num":查看调用的详细信息;down:返回栈列表;l:显示详细代码信息;p:输出数值。
2. 添加全局断点( Exception BreakPoint):
2.1 添加步骤:
1. In the bottom-left corner of the breakpoints navigator, click the Add button.
2. Choose Add Exception Breakpoint.
3. Choose the type of exception from the Exception pop-up menu.
4. Choose the phase of the exception handling process at which you want program execution to stop.
5. Click Done.
2.2 使用场景:
程序因为SIGABRT而crash,想要定位到导致crash的行。
然后右键单击该断点选择move breakpoint to,选择User,即可以在所有项目中起作用
3. 添加符号断点( Symbolic BreakPoint):
3.1 断点执行的时机:Symbolic breakpoints stop program execution when a specific function or method starts executing
3.2 添加步骤:
1. Steps In the bottom-left corner of the breakpoint navigator, click the Add button.
2. Choose Add Symbolic Breakpoint.
3. Enter the symbol name in the Symbol field.
4. Click Done.
3.3 使用场景:
当想让系统在某个指定条件处中断时,设置相应的断点。
比如:
objc_exception_throw:在系统抛出异常处设置断点。
-[NSException raise]:
还可添加输入malloc_error_break的symbolic断点,以跟踪调试释放了2次的对象
4. 设置NSZombieEnabled、MallocStackLogging、NSAutoreleaseFreedObjectCheckEnabled、NSDebugEnabled:
4.1 设置方法:
1. Product->Edit Scheme...->Run...->EnvironmentVariables.
2. add NSZombieEnabled,set the value with YES
3. add MallocStackLogging, set the value with YES.
4. add NSAutoreleaseFreedObjectCheckEnabled, set the value with YES.
5. add NSDebugEnabled, set the value with YES.
4.2 使用场景:
主要为了解决EXC_BAD_ACCESS问题,MallocStackLogging用来启用malloc记录(使用方式 malloc_history ${App_PID} ${Object_instance_addr})。
4.3 需要注意的问题
NSZombieEnabled只能在调试的时候使用,千万不要忘记在产品发布的时候去掉,因为NSZombieEnabled不会真正去释放dealloc对象的内存。
5. 重写respondsToSelector方法
5.1 实现方式
#ifdef _FOR_DEBUG_
-(BOOL) respondsToSelector:(SEL)aSelector {
printf("SELECTOR: %s\\n", [NSStringFromSelector(aSelector) UTF8String]);
return [super respondsToSelector:aSelector];
}
#endif
5.2 使用方法:
需要在每个object的.m或者.mm文件中加入上面代码(应该可以使用类属实现),并且在other c flags中加入-D _FOR_DEBUG_(记住请只在Debug Configuration下加入此标记)。这样当你程序崩溃时,Xcode的console上就会准确地记录了最后运行的object的方法。
参考文章:
1. Xcode GDB 调试:http://blog.csdn.net/ch_soft/article/details/7005998
2. XCode的一些调试技巧:http://blog.csdn.net/kesalin/article/details/7222153
3. About the Breakpoint
Navigator:http://developer.apple.com/library/mac/#recipes/xcode_help-breakpoint_navigator/articles/about_breakpoint_navigator.html#//apple_ref/doc/uid/TP40010433-CH6-SW1
4. 当程序崩溃的时候怎么办 part-1:http://article.ityran.com/archives/1006
5. 当程序崩溃的时候怎么办 Part-2:http://article.ityran.com/archives/1143
6. Memory Usage Performance
Guidelines:https://developer.apple.com/library/mac/#documentation
/performance/Conceptual/ManagingMemory/ManagingMemory.html#//apple_ref/doc/uid/10000160-SW1