Objective-C Xcode4中的debugging技巧?

通过Flex-Flash IDE,我可以在代码中设置断点,并在运行时查看相应窗口中variables的值。

现在,我想出了在Xcode中可以find'variables'的窗口,我可以看到所有的variables,但是这些variables的值不能被看到。 我所有的是数据types和一堆hex数字(指针?)。

我该如何debugging我的代码? 我在哪里可以看到我的variables的值,而不必logging在我的代码?

我想用一堆键/值对来查看NSDictionary值。 但也是任何其他NSObject的事情。 我已经阅读了一些关于重写描述方法的内容,但是关于本地对象呢?

使用GDB进行debugging

XCode为您提供了一个GDBdebugging器,就像Jano在他的评论中所说的那样,您可以使用像po(打印对象)这样的GDB命令来查看一个对象。

 po myObject po myDictionary po myArray 

要打印像int,float这样的图元,可以使用printppx (以hexpx查看数字)

 print myInt p myInt px myInt 

你也可以看到运行命令的结果。 例如,要查看一个string的长度,你可以这样做:

 p (int) [myString length] 

如果你不把这个返回值转换成int,我相信你会在控制台中看到一些抱怨。

要查看一个UIView的框架(CGRect结构types),你可以这样做:

 p (CGRect) [myView frame] 

最后,如果你重写一个类的description方法,你可以自定义它在写入控制台或甚至NSLog时的显示方式。 如果你这样做[NSString stringWithFormat:@"My object... %@", myObj]将调用该对象的描述方法。

 - (NSString*) description { return @"This is the object description!"; } 

另一个好的阅读是如何在Xcode基于对象的string属性设置条件断点?


日志提示

如果你需要NSLog消息,但只有在debugging版本中,你可能会喜欢我在工作中使用的DLogmacros:

 #ifdef DEBUG #define DLog(...) NSLog(__VA_ARGS__) #else #define DLog(...) /* */ #endif 

它和NSLog一样工作,只是在非DEBUG版本上编译。 NSLog实际上可能是一个性能打击,再加上你可能不希望有一些消息泄漏出你的日志。

我们把这个macros放在预编译头文件(MyApp-Prefix.pch)中,这样它就包含在所有的项目文件中。


倾销variables

您的评论问到如何转储对象的所有variables而无需编写代码。 我知道没有build立这样做的方式。 但是,您可以尝试使用reflection。 我有一个实现,将允许你做这样的事情:

 po [someObj dump] 

您可以在NSObject上创build一个类别,为所有NSObjecttypes添加一个方法,以转储您之后的信息。 我借用了Objective C Introspection / Reflection中的代码来启动代码,但添加了包含属性值的代码。

NSObject(DebuggingAid)类别:

 #import <objc/runtime.h> @interface NSObject (DebuggingAid) - (NSString*)dump; @end @implementation NSObject (DebuggingAid) - (NSString*)dump { if ([self isKindOfClass:[NSNumber class]] || [self isKindOfClass:[NSString class]] || [self isKindOfClass:[NSValue class]]) { return [NSString stringWithFormat:@"%@", self]; } Class class = [self class]; u_int count; Ivar* ivars = class_copyIvarList(class, &count); NSMutableDictionary* ivarDictionary = [NSMutableDictionary dictionaryWithCapacity:count]; for (int i = 0; i < count ; i++) { const char* ivarName = ivar_getName(ivars[i]); NSString *ivarStr = [NSString stringWithCString:ivarName encoding:NSUTF8StringEncoding]; id obj = [self valueForKey:ivarStr]; if (obj == nil) { obj = [NSNull null]; } [ivarDictionary setObject:obj forKey:ivarStr]; } free(ivars); objc_property_t* properties = class_copyPropertyList(class, &count); NSMutableDictionary* propertyDictionary = [NSMutableDictionary dictionaryWithCapacity:count]; for (int i = 0; i < count ; i++) { const char* propertyName = property_getName(properties[i]); NSString *propertyStr = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]; id obj = [self valueForKey:propertyStr]; if (obj == nil) { obj = [NSNull null]; } [propertyDictionary setObject:obj forKey:propertyStr]; } free(properties); NSDictionary* classDump = [NSDictionary dictionaryWithObjectsAndKeys: ivarDictionary, @"ivars", propertyDictionary, @"properties", nil]; NSString *dumpStr = [NSString stringWithFormat:@"%@", classDump]; return dumpStr; } @end 

假设你已经设置了一个断点,并且你的程序已经停止了,你会在debugging区左边的variables视图中看到一个variables列表。 每个都有一个价值。 如果它是一个原始types,那么没有什么可以看到的,但如果它是一个对象,所有你得到的是地址和一个公开的箭头。 公开箭头将显示对象的所有实例variables。 这样你可以深入到你想要的任何东西。

很多时候你有一个对象为一个属性公开一个getter,但是不要显式地存储它,或者以另一种forms存储它。 debugging器不够聪明,不能遵循这些规则,但是可以在右边的GDB窗口中评估任何Objective-Cexpression式,包括执行方法调用。 在我看来,最有用的命令是“p”打印原始对象和“po”打印对象types的描述。

在基础types中,variables视图窗口似乎足够聪明,能够列出一个NSArray的内容,但不够聪明,给你任何有关字典的意义。 你会被告知例如'1键/值对',但没有其他更多。 所以你被困在右边的窗口,然后input“po字典”来查看内容。

我个人认为,Xcode中的graphics状态检查是非常薄弱的​​, 我发现debugging器是完全有效的,并且可以很容易地跟踪我的代码并发现错误,因为我学会了使用右侧的控制台窗口。