XCODE调试技巧收集

前记:编写代码过程中,出现错误、异常是不可避免的,这个时候,就体现了调试的重要性,下面就总结一下,平常我自己使用的一些调试技巧,以及汇总网络上其他网友使用的技巧。(ps以后有新的调试技巧,我也会一并更新)

1、使用僵尸变量(NSZombieEnabled)

 2、重写object的respondsToSelector方法

在iphone开发的时候EXC_BAD_ACCESS这个bug时不容易找到原因的。

首先说一下EXC_BAD_ACCESS 这个错误,可以这么说,90%的错误来源在于对一个已经释放的对象进行release操作,或者操作一个在循环代码中被修改的序列中的对象。虽然使用NSZombieEnabled变量可以帮助你找到问题所在,但有的时候,即使通过设置NSZombieEnabled变量,还是不能定位到问题所在,这个时候,你可以试试重写object的respondsToSelector方法,显示出现EXEC_BAD_ACCESS前访问的最后一个object,下面是具体的步骤:
a、在每个类并且在 other c flags中加入-D _FOR_DEBUG_(记住请只在Debug Configuration下加入此标记)。这样当你程序崩溃时,Xcode的console上就会准确地记录了最后运行的object的方法。的实现文件(.m,.mm)文件中,添加如下代码:
[cpp] 
-(BOOL) respondsToSelector : (SEL)aSelector { 
    printf("SELECTOR: %s\n", [NSStringFromSelector(aSelector) UTF8String]); 
    return [super respondsToSelector:aSelector]; 

b、并且在 other c flags中加入-D _FOR_DEBUG_(记住请只在Debug Configuration下加入此标记)。这样当你程序崩溃时,Xcode的console上就会准确地记录了最后运行的object的方法。

3、让XCode反馈足够多的信息

在Edit–>Scheme里面 找到Arguments ,在Environment Variables这里添加
把下面2个值设置成YES
NSAutoreleaseFreedObjectCheckEnabled
NSDebugEnabled
这种方法非常好用,建议在建立一个工程的时候,加入此设置

4、设置全局异常断点

在程序抛出异常时候,往往需要定位到异常
键入快捷键 cmd + 6 进入断点窗口,点击左下角的"+"按钮,选择弹出框的“Add Exception BreakPoint”项,如下图所示:XCODE调试技巧收集_第1张图片

然后使用默认设置,点击"done"按钮,设置全局异常断点就完成了



其他

使用xcode调试僵尸对象

   
在写obj-c代码的时候,僵尸对象是比较麻烦的问题.僵尸对象是指,提前释放内存的对象.对于iphone/mac程序来说,出现这个问题的原因一般有2个,第一,程序员自己过早释放内存,第二,使用了外部框架导致的.第一点很容易查出来,第二点来说,主要是因为外部框架一般会使用autorelease,如果对框架怎么运行不清楚的话,提前手动释放内存,就会使自动释放内存的时候出错.
举例来说:
 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

  NSData* data = [NSData dataWithBytes:"asklaskdxjgr" length:12];

[data release];

  [pool release];
由于NSData的dataWithBytes是类方法,并且会设置autorelease,所以在pool释放内存的时候,data已经是僵尸对象.

解决方法来说一般也是2个,第一个所有对象都使用autorelease方式,但是这种方式的问题在于performance不怎么好,而且也不利于程序员水平的提高.第二个就是找到僵尸对象,查看其调用关系,理顺内存释放顺序.那么找到僵尸对象就成为了急需解决的问题.

苹果有个头文件,叫NSDebug.h,具体在 这里. 很久以前就是靠引入这个头文件来解决问题.当然随着obj-c2.0的引入,我们可以不再用这么古老的方式.新的做法如下:

1 在xode里右击可执行文件,选择getinfo-->arguments-->Variables to beset in the ENV

2 添加以下变量
  NSDebugEnabled

  NSZombieEnabled

  MallocStackLogging

  MallocStackLoggingNoCompact

?设置他们的值为YES.



3 在debug模式下运行程序,到pool release的时候,会在console上看到:

2010-12-25 08:01:38.644 autoreleasebug[3939] *** *** Selector 'release'

  sent to dealloced instance 0xa4e10 of class NSConcreteData.

这就说明有僵尸对象出现,给了进程id--3939,对象内存地址--0xa4e10.



4 接下来在console里敲shell malloc_history pid(3939) address(0xa4e10).得到调用关系如下:



Call [2] [arg=24]: thread_a000a1ec |0x0 | _dyld_start | _start | main | NSApplicationMain

 | -[NSApplication run] | -[NSApplication sendEvent:] | -[NSWindow sendEvent:]

 | -[NSControl mouseDown:] | -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:]

 | -[NSCell trackMouse:inRect:ofView:untilMouseUp:] | -[NSCell _sendActionFrom:]

 | -[NSControl sendAction:to:] | -[NSApplication sendAction:to:from:] | -[MEController 

newCity:] | -[MECityEditor editCity:otherCities:] | -[NSApplication runModalForWindow:]

 | -[NSApplication _realDoModalLoop:peek:] | -[NSApplication nextEventMatchingMask:

untilDate:inMode:dequeue:] | _DPSNextEvent | BlockUntilNextEventMatchingListInMode

 | ReceiveNextEventCommon | RunCurrentEventLoopInMode | CFRunLoopRunSpecific

 | __CFRunLoopRun | __CFRunLoopDoObservers | _handleWindowNeedsDisplay | -[NSWindow 

displayIfNeeded] | -[NSView displayIfNeeded] | -[NSView _displayRectIgnoringOpacity:

isVisibleRect:rectIsVisibleRectForView:] | -[NSThemeFrame 

_recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:

topView:] | -[NSFrameView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:

rectIsVisibleRectForView:topView:] | -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:

isVisibleRect:rectIsVisibleRectForView:topView:] | -[NSView

_recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:]

 | -[NSView(NSInternal) _getDirtyRects:clippedToRect:count:boundingBox:] | -[NSRegion 

mutableCopy] | NSAllocateObject | _internal_class_createInstanceFromZone | malloc_zone_ca

lloc



根据这个调用关系,我们就可以哪个对象被提前释放了,从而修改程序.


你可能感兴趣的:(XCODE调试技巧收集)