前记:编写代码过程中,出现错误、异常是不可避免的,这个时候,就体现了调试的重要性,下面就总结一下,平常我自己使用的一些调试技巧,以及汇总网络上其他网友使用的技巧。(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”项,如下图所示:
然后使用默认设置,点击"done"按钮,设置全局异常断点就完成了
其他
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSData* data = [NSData dataWithBytes:"asklaskdxjgr" length:12]; [data release]; [pool release];由于NSData的dataWithBytes是类方法,并且会设置autorelease,所以在pool释放内存的时候,data已经是僵尸对象.
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 根据这个调用关系,我们就可以哪个对象被提前释放了,从而修改程序.