views:

193

answers:

3

The -description method for NSArray will nest recursive calls as in:

2009-05-15 14:28:09.998 TestGUIProject[29695:813] (
    a, // Array1 item 1
        ( // Array2, a second array, nicely indented another 4 spaces
        a // Item in Array2
    ) // End of Array2
) // End of Array1

I want to do something similar for my own custom classes (using a script I'm writing).

What I don't know is how to add the extra level of indentation when the recursively called object adds new lines of its own.

What I have is the following:

- (NSString *)description {
    return [NSString stringWithFormat:@"{{{\n"
            @"    prop1: %@\n"
            @"    prop2: %@\n"
            @"    prop3: %@\n"
            @"    prop4: %@\n"
            @"}}}",
            self.prop1,
            self.prop2,
            self.prop3,
            self.prop4];
}

But this breaks down as soon as one of the properties is an NSArray or another object using this same description format, because it doesn't nest nicely.

Instead you get:

2009-05-15 14:25:50.899 TestApp[29636:813] {{{
    prop1: SomeValue1
    prop2: ( // Prop 2 is an Array of strings
    "String1", // Note no additional level of indentation as in the NSArray example
    "String2",
    "String3",
    "String4"
)
    prop3: SomeValue3
    prop4: SomeValue4
}}}

How do I do I get the additional levels of nesting?

A: 

You may have to ditch relying on the description in NSArray. Perhaps you should write a method to iterate through the array and indent as necessary yourself while adding to the NSString. You'll probably have to use an NSMutableString and pass it around so the strings can be appended to it.

Edit

Based on your comment, I'd then say to use the objc_* methods to reflect on whatever object has been passed to your debugging method. From there you can pull all the properties or instance variables and iterate through them. You could also use a conditional to check the type of the ivar, and if it's a standard collection class such as NSArray or NSDictionary, iterate over it yourself to output the data in the format you want (and then of course handle other types of objects and all the primitives in their own way).

Marc W
The issue with that is that I'm trying to write a script that lets use all the instance variables for a class as input and produces a good description method from it for debugging purposes and such. It's much more difficuly if I have to specifically parse NSArray/Dictionarys/subclasses of the aforementioned, etc and handle them specially.
Lawrence Johnston
A: 

This actually works for my purposes:

[[self.prop2 description] stringByReplacingOccurrencesOfString:@"\n" withString:@"\n    "]
Lawrence Johnston
+6  A: 

What you want is this function, available on NSArray and NSDictionary:

- (NSString *) descriptionWithLocale: (id) locale indent: (NSUInteger) level;

Specify an indent of 1 to have your nested array or dictionary indent everything it prints by the specified amount.

Jim Dovey
It's a method, not a function…
Mike Abdullah
Jim Dovey