NSDictionary-like beautiful print in the debugger (or in the log)

This has been undermining me for a while. How can I counteract the ugly shielding that occurs when objects are dumped in the debugger using po foo(or through NSLog). I have tried many implementation approaches -descriptionor to -debugDescriptionno avail.

Given this simple class

@interface Foo : NSObject
@property NSDictionary* dict;
@end

@implementation Foo
- (NSString *)description {
    // super.description for the <{classname} pointer> output
    return [NSString stringWithFormat:@"%@ %@", super.description, self.dict];
}
@end

And far-fetched use

Foo* f0 = [[Foo alloc] init];
f0.dict = @{ @"value": @0, @"next": NSNull.null };
Foo* f1 = [[Foo alloc] init];
f1.dict = @{ @"value": @1, @"next": f0 };
Foo* f2 = [[Foo alloc] init];
f2.dict = @{ @"value": @2, @"next": f1 };

We get a good conclusion for f0

(lldb) po f0
<Foo: 0x8cbc410> {
    next = "<null>";
    value = 0;
}

Permissible output for f1

(lldb) po f1
<Foo: 0x8cbc480> {
    next = "<Foo: 0x8cbc410> {\n    next = \"<null>\";\n    value = 0;\n}";
    value = 1;
}

And a terrifying conclusion for f2

(lldb) po f2
<Foo: 0x8cbc4b0> {
    next = "<Foo: 0x8cbc480> {\n    next = \"<Foo: 0x8cbc410> {\\n    next = \\\"<null>\\\";\\n    value = 0;\\n}\";\n    value = 1;\n}";
    value = 2;
}

It becomes difficult to parse quickly when debugging a hierarchy of real-world objects. I assume that there is one more trick that I have been missing since resetting a similarly nested NSDictionary

NSDictionary* d0 = @{ @"value": @0, @"next": NSNull.null };
NSDictionary* d1 = @{ @"value": @1, @"next": d0 };
NSDictionary* d2 = @{ @"value": @2, @"next": d1 };

Supports padding and avoids elusive hell.

(lldb) po d2
{
    next =     {
        next =         {
            next = "<null>";
            value = 0;
        };
        value = 1;
    };
    value = 2;
}

UPDATE

Switch to -debugDescriptionand just forward to the dictionary

@implementation Foo
- (NSString *)debugDescription {
    return self.dict.debugDescription;
}
@end

(lldb) po f2
{
    next = "<Foo: 0x8b70e20>";
    value = 2;
}

NSDictionary -description, , -debugDescription. -

@implementation Foo
- (NSString *)description {
    return self.dict.description;
}
- (NSString *)debugDescription {
    return self.dict.debugDescription;
}
@end

,

(lldb) po f2
{
    next = "{\n    next = \"{\\n    next = \\\"<null>\\\";\\n    value = 0;\\n}\";\n    value = 1;\n}";
    value = 2;
}
+4
2

TL; DR;

NSContainers-PrettyPrint docs.

descriptionWithLocale:indent:. , . SO. descriptionWithLocale:indent: , Foundation - " ".

, radar, NSContainers-PrettyPrint. . ( CocoaPods, ).

NSContainers-PrettyPrint , , JRSwizzle. DEBUGPRINT_ALL DEBUGPRINT_SWIZZLE DEBUG. , descriptionWithLocale:indent: fs_ * helpers .

Foo

@implementation Foo
- (NSString*)description
{
    return [NSString stringWithFormat:@"%@ %@", super.description, self.dict.description];
}

- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
{
    NSString * indent = [NSString fs_stringByFillingWithCharacter:' ' repeated:fspp_spacesPerIndent*level];
    NSMutableString * str = [[NSMutableString alloc] init];
    [str fs_appendObjectStartWithIndentString:indent caller:self];
    [str appendString:[self.dict descriptionWithLocale:locale indent:level+1]];
    [str fs_appendObjectEnd];
    return str;
}
@end

f0, f1 f2

(lldb) po f0
<Foo: 0x8a385c0> {
    value = 0;
    next = <null>;
}
(lldb) po f1
<Foo: 0x8a38630> {
    value = 1;
    next = <Foo:0x8a385c0        {
            value = 0;
            next = <null>;
        }>;
}
(lldb) po f2
<Foo: 0x8a38660> {
    value = 2;
    next = <Foo:0x8a38630        {
            value = 1;
            next = <Foo:0x8a385c0                {
                    value = 0;
                    next = <null>;
                }>;
        }>;
}

descriptionWithLocale:indent: , - .

+4

( NSDictionary description - , char), , NSArray NSDictionary -[NSObject respondsToSelector:@selector(descriptionWithLocale:indent:). .

, NSProxy, . :

NSObject *proxy = [LoggingProxy proxyWithTarget:[[NSObject alloc] init]];
NSLog(@"%@", @[proxy]);

:

message: isNSString__
message: isNSDictionary__
message: isNSArray__
message: isNSData__

2014-05-29 15:29:22.728 Proxy[36219:303] (
    "<LoggingProxy: 0x100103510>"
)
Program ended with exit code: 0

:

#if DEBUG
- (BOOL) isNSDictionary__
{
    return YES;
}
#endif

NSArray NSDictionary, , , -[NSObject respondsToSelector:@selector(descriptionWithLocale:indent:). , YES, descriptionWithLocale:indent:, .

#if DEBUG. , , Xcode.

+2

Source: https://habr.com/ru/post/1523655/


All Articles