Xcode4中的Objective-C调试技巧?

时间:2022-09-19 06:10:38

Coming from a Flex-Flash IDE, I was able to set breakpoints in my code and at runtime view the values of my variables in the corresponding window.

来自Flex-Flash IDE,我能够在我的代码中设置断点,并在运行时查看相应窗口中变量的值。

Now, I figured out where I can find the 'variables' window in Xcode and I can see all my variables there BUT the values of those variables can't be seen. All I have is the data type and a bunch of hex numbers (pointers?).

现在,我想出了在Xcode中可以找到'变量'窗口的位置,我可以看到我所有的变量但是这些变量的值无法看到。我只有数据类型和一堆十六进制数字(指针?)。

How am I supposed to debug my code? Where can I see the values of my variables without having to log them in my code?

我该如何调试我的代码?我在哪里可以看到变量的值而无需在我的代码中记录它们?

I am trying to see the values of a NSDictionary with a bunch of key/value pairs. But also any other NSObject for that matter. I have read something about overriding the description method but what about native objects?

我试图用一堆键/值对来查看NSDictionary的值。但也有任何其他NSObject。我已经阅读了一些关于覆盖描述方法的内容但是本机对象呢?

2 个解决方案

#1


39  

Debugging with GDB

XCode gives you a GDB Debugger, so like Jano said in his comment, you can use GDB commands like po (print object) to view an object.

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

po myObject
po myDictionary
po myArray

To print primitives like int, float, you can use print, p, and px (to view the number in hex)

要打印像int,float这样的基元,可以使用print,p和px(以十六进制查看数字)

print myInt
p myInt
px myInt

You can also see the result of running commands. For example, to view a string length you could do:

您还可以查看运行命令的结果。例如,要查看字符串长度,您可以执行以下操作:

p (int) [myString length]

If you do not cast the return to an int, I believe you'll see some complaining in the console.

如果你没有将返回转换为int,我相信你会在控制台中看到一些抱怨。

To view a UIView's frame (CGRect struct type), you can do:

要查看UIView的框架(CGRect结构类型),您可以执行以下操作:

p (CGRect) [myView frame]

Lastly, if you override the description method of a class, you can customize how it displays when written to the console or even to an NSLog for that matter. If you do [NSString stringWithFormat:@"My object... %@", myObj] the description method of that object will be called.

最后,如果覆盖类的描述方法,则可以自定义在写入控制台或甚至NSLog时的显示方式。如果你执行[NSString stringWithFormat:@“我的对象...%@”,myObj]将调用该对象的描述方法。

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

Another good read is How to set a conditional breakpoint in Xcode based on an object string property?

另一个好的读物是如何根据对象字符串属性在Xcode中设置条件断点?


Log Tip

If you want NSLog messages but only in debug builds, you might like the DLog macro we use at my work:

如果您想要NSLog消息但仅在调试版本中,您可能会喜欢我在工作中使用的DLog宏:

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

It works just like NSLog except that it is compiled out on non-DEBUG builds. NSLog can actually be a performance hit, plus you may not want some messages spilling out in your logs.

它的工作方式与NSLog类似,只是它是在非DEBUG构建版本上编译的。 NSLog实际上可能会受到性能影响,而且您可能不希望某些消息在您的日志中溢出。

We put this macro in the precompiled header file (MyApp-Prefix.pch) so that it gets included in all the project files.

我们将此宏放在预编译的头文件(MyApp-Prefix.pch)中,以便它包含在所有项目文件中。


Dumping Variables

Your comment asked about how to dump all variables of an object without writing code. I know of no built in way to do this. However, you might try using reflection. I have an implementation that will allow you to do something like:

您的评论询问如何在不编写代码的情况下转储对象的所有变量。我知道没有内置的方法来做到这一点。但是,您可以尝试使用反射。我有一个实现,可以让你做类似的事情:

po [someObj dump]

You can make a category on NSObject to add a method to all NSObject types that will dump the information you're after. I borrowed code from Objective C Introspection/Reflection to start off the code, but added code to include property values.

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

NSObject (DebuggingAid) category:

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

#2


5  

Assuming you've set a breakpoint and your program has stopped at it, you'll see a list of variables in the variables view within the left portion of the debug area. Each has a value. If it's a primitive type then there's nothing more to see, but if it's an object all you get is the address and a disclosure arrow. The disclosure arrow will show you all the instance variables of the object. That way you can drill down to whatever you're looking for.

假设您已设置断点并且程序已停止,您将在调试区域左侧的变量视图中看到变量列表。每个都有一个值。如果它是一个原始类型,那么没有什么可看的,但如果它是一个对象,你得到的只是地址和公开箭头。公开箭头将显示对象的所有实例变量。通过这种方式,您可以深入了解您正在寻找的任何内容。

Quite a lot of the time you have objects that expose a getter for a property but don't store it explicitly or store it in another form. The debugger isn't smart enough to follow those, but you can evaluate any Objective-C expression you want in the GDB window on the right, including performing method calls. In my opinion the most useful commands are 'p' to print a primitive object and 'po' to print the description of an object type.

很多时候你有对象公开属性的getter但是没有显式存储它或者以另一种形式存储它。调试器不够智能,无法遵循这些,但您可以在右侧的GDB窗口中评估所需的任何Objective-C表达式,包括执行方法调用。在我看来,最有用的命令是'p'来打印原始对象,'po'来打印对象类型的描述。

Of the Foundation types, the variable view window seems to be smart enough to be able to list the contents of an NSArray but not smart enough to give you anything meaningful about a dictionary. You get told e.g. '1 key/value pair' but nothing more than that. So you're stuck going over into the window on the right and typing 'po dictionary' to see contents.

在Foundation类型中,变量视图窗口似乎足够聪明,能够列出NSArray的内容,但不够聪明,无法为您提供有关字典的任何有意义的内容。你被告知,例如'1键/值对'但仅此而已。所以你被困在右边的窗口,输入'po dictionary'来查看内容。

My personal opinion is that the graphical state inspection in Xcode is extremely weak; I find the debugger completely effective and can easily track my code and find bugs only because I've learnt to use the console window on the right.

我个人认为Xcode中的图形状态检查非常弱;我发现调试器完全有效,并且可以轻松跟踪我的代码并发现错误,因为我已经学会了使用右侧的控制台窗口。

#1


39  

Debugging with GDB

XCode gives you a GDB Debugger, so like Jano said in his comment, you can use GDB commands like po (print object) to view an object.

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

po myObject
po myDictionary
po myArray

To print primitives like int, float, you can use print, p, and px (to view the number in hex)

要打印像int,float这样的基元,可以使用print,p和px(以十六进制查看数字)

print myInt
p myInt
px myInt

You can also see the result of running commands. For example, to view a string length you could do:

您还可以查看运行命令的结果。例如,要查看字符串长度,您可以执行以下操作:

p (int) [myString length]

If you do not cast the return to an int, I believe you'll see some complaining in the console.

如果你没有将返回转换为int,我相信你会在控制台中看到一些抱怨。

To view a UIView's frame (CGRect struct type), you can do:

要查看UIView的框架(CGRect结构类型),您可以执行以下操作:

p (CGRect) [myView frame]

Lastly, if you override the description method of a class, you can customize how it displays when written to the console or even to an NSLog for that matter. If you do [NSString stringWithFormat:@"My object... %@", myObj] the description method of that object will be called.

最后,如果覆盖类的描述方法,则可以自定义在写入控制台或甚至NSLog时的显示方式。如果你执行[NSString stringWithFormat:@“我的对象...%@”,myObj]将调用该对象的描述方法。

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

Another good read is How to set a conditional breakpoint in Xcode based on an object string property?

另一个好的读物是如何根据对象字符串属性在Xcode中设置条件断点?


Log Tip

If you want NSLog messages but only in debug builds, you might like the DLog macro we use at my work:

如果您想要NSLog消息但仅在调试版本中,您可能会喜欢我在工作中使用的DLog宏:

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

It works just like NSLog except that it is compiled out on non-DEBUG builds. NSLog can actually be a performance hit, plus you may not want some messages spilling out in your logs.

它的工作方式与NSLog类似,只是它是在非DEBUG构建版本上编译的。 NSLog实际上可能会受到性能影响,而且您可能不希望某些消息在您的日志中溢出。

We put this macro in the precompiled header file (MyApp-Prefix.pch) so that it gets included in all the project files.

我们将此宏放在预编译的头文件(MyApp-Prefix.pch)中,以便它包含在所有项目文件中。


Dumping Variables

Your comment asked about how to dump all variables of an object without writing code. I know of no built in way to do this. However, you might try using reflection. I have an implementation that will allow you to do something like:

您的评论询问如何在不编写代码的情况下转储对象的所有变量。我知道没有内置的方法来做到这一点。但是,您可以尝试使用反射。我有一个实现,可以让你做类似的事情:

po [someObj dump]

You can make a category on NSObject to add a method to all NSObject types that will dump the information you're after. I borrowed code from Objective C Introspection/Reflection to start off the code, but added code to include property values.

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

NSObject (DebuggingAid) category:

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

#2


5  

Assuming you've set a breakpoint and your program has stopped at it, you'll see a list of variables in the variables view within the left portion of the debug area. Each has a value. If it's a primitive type then there's nothing more to see, but if it's an object all you get is the address and a disclosure arrow. The disclosure arrow will show you all the instance variables of the object. That way you can drill down to whatever you're looking for.

假设您已设置断点并且程序已停止,您将在调试区域左侧的变量视图中看到变量列表。每个都有一个值。如果它是一个原始类型,那么没有什么可看的,但如果它是一个对象,你得到的只是地址和公开箭头。公开箭头将显示对象的所有实例变量。通过这种方式,您可以深入了解您正在寻找的任何内容。

Quite a lot of the time you have objects that expose a getter for a property but don't store it explicitly or store it in another form. The debugger isn't smart enough to follow those, but you can evaluate any Objective-C expression you want in the GDB window on the right, including performing method calls. In my opinion the most useful commands are 'p' to print a primitive object and 'po' to print the description of an object type.

很多时候你有对象公开属性的getter但是没有显式存储它或者以另一种形式存储它。调试器不够智能,无法遵循这些,但您可以在右侧的GDB窗口中评估所需的任何Objective-C表达式,包括执行方法调用。在我看来,最有用的命令是'p'来打印原始对象,'po'来打印对象类型的描述。

Of the Foundation types, the variable view window seems to be smart enough to be able to list the contents of an NSArray but not smart enough to give you anything meaningful about a dictionary. You get told e.g. '1 key/value pair' but nothing more than that. So you're stuck going over into the window on the right and typing 'po dictionary' to see contents.

在Foundation类型中,变量视图窗口似乎足够聪明,能够列出NSArray的内容,但不够聪明,无法为您提供有关字典的任何有意义的内容。你被告知,例如'1键/值对'但仅此而已。所以你被困在右边的窗口,输入'po dictionary'来查看内容。

My personal opinion is that the graphical state inspection in Xcode is extremely weak; I find the debugger completely effective and can easily track my code and find bugs only because I've learnt to use the console window on the right.

我个人认为Xcode中的图形状态检查非常弱;我发现调试器完全有效,并且可以轻松跟踪我的代码并发现错误,因为我已经学会了使用右侧的控制台窗口。