16

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.

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?).

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?

Monolo
  • 18,205
  • 17
  • 69
  • 103
Jovan
  • 2,640
  • 2
  • 24
  • 34
  • 1
    Right click the variables and select "print description". Or focus on the console at the green "(gdb)" prompt, and type: `po objectName` or `po [object message]`. For a dictionary type `po [dic objectForKey:@"somekey"]`. – Jano Oct 04 '11 at 16:11

2 Answers2

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.

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)

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.

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

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.

- (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?


Log Tip

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

#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.

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


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 (DebuggingAid) category:

#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
Community
  • 1
  • 1
Sam
  • 26,946
  • 12
  • 75
  • 101
  • Forgot to mention, but if you do `po myDictionary` you should see the key/value pairs you were originally after. – Sam Oct 04 '11 at 20:53
  • 1
    Great tips! Is there a way to recursively print an object? For example if I have a Person object with a NSString 'address' property inside it, I now call 'po [Person address]. I'd like to see all it's properties (let's say name, phone, etc) at once without having to write my own implementation of 'description' method that returns them. – Jovan Oct 05 '11 at 09:12
  • I added a category on NSObject in the answer that will get you part of the way there. This isn't recursive. You can make it recursive, but you'll need to put something in place to not explore cyclic references. – Sam Oct 05 '11 at 17:16
  • Also see [Xcode 4.2 debug doesn't symbolicate stack call](http://stackoverflow.com/a/8870078/590956) for how to get a stack trace when all you are given is a collection of memory addresses (hex numbers). In addition, you can use `info symbol 0x123456` where 0x123456 should be replaced by a memory address. This will spit out symbol information at that memory address (like a function name) – Sam Mar 15 '12 at 16:31
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.

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.

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.

Tommy
  • 99,986
  • 12
  • 185
  • 204