调试器(或日志)中的NSDictionary-like漂亮打印 [英] NSDictionary-like pretty-print in the debugger (or log)

查看:125
本文介绍了调试器(或日志)中的NSDictionary-like漂亮打印的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这段时间一直在欺骗我。如何解决在调试器中使用 po foo (或通过 NSLog )转储对象时发生的丑陋转义。我尝试了许多方法来实现 -description -debugDescription 无效。

This has been bugging me for a while. How do I counteract the ugly escaping that happens when dumping objects in the debugger with po foo (or via NSLog). I've tried numerous approaches to implementing -description or -debugDescription to no avail.

给定这个简单的类

@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

并设计使用

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 };

我们为 f0

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

f1的容忍输出

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

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;
}

调试现实世界的对象层次结构时,这很难解析。我假设还有一些其他的技巧,因为我倾销了一个类似的嵌套NSDictionary

This gets hard to parse fast when debugging real world object hierarchies. I'm assuming there's some other trick I'm missing since dumping a similarly nested NSDictionary

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

保持缩进,避免转义地狱

Maintains the indenting and avoids the escaping hell

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

更新

切换到 -debugDescription ,只需转发到字典

Switching to -debugDescription and simply forwarding to the dictionary

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

丢失递归输出

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

内部 NSDictionary 必须要依靠 -description ,我在这个例子中没有实现,只有 -debugDescription 。切换到如下所示的

Internally NSDictionary must be relying on -description which I'm not implementing in this example, only -debugDescription. Switching to something like the following

@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;
}


推荐答案

TL; DR; h3>

使用 NSContainers-PrettyPrint 仔细阅读 docs

经过更多的搜索,我发现了 descriptionWithLocale:indent: 方法。如所记载的,我应该可以在我自己的类中实现这一点,以实现所需的漂亮打印格式。但是,在一些尝试失败后,我发现一个类似的SO问题。结果 descriptionWithLocale:indent:只有在由于安全性问题而对基础容器类进行子类化时才起作用。

After much more searching I discovered the descriptionWithLocale:indent: method. As documented, I should've been able to implement this in my own classes to achieve the desired pretty-print formatting. However, after some failed attempts I found a similar SO question. Turns out descriptionWithLocale:indent: only works if you subclass a Foundation container class because of "security concerns".

不满意的方法我继续挖掘,并发现这个雷达,但也是一个解决方案在 NSContainers-PrettyPrint 。经过一番试错,我把事情做得很好。 (它不是在CocoaPods,所以你必须手动添加)。

Unsatisfied with that approach I continued digging and found this radar but also a solution in NSContainers-PrettyPrint. After some trial and error I got things working decently well. (It's not on CocoaPods so you have to add it manually).

一旦NSContainers-PrettyPrint被添加,你可能会希望 JRSwizzle 。然后在DEBUG目标预处理器宏中定义 DEBUGPRINT_ALL DEBUGPRINT_SWIZZLE 。最后,您可以根据 descriptionWithLocale:indent:方法/String-Tools.mdrel =nofollow> fs_ * helpers 最佳做法

Once NSContainers-PrettyPrint is added you'll probably want JRSwizzle too. Then define DEBUGPRINT_ALL and DEBUGPRINT_SWIZZLE in your DEBUG targets preprocessor macros. Finally, you can implement your descriptionWithLocale:indent: methods in terms of the fs_* helpers and best practices.

使用与我的问题相同的 Foo 例如

Using the same Foo from my question as an example

@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 实例

Would produce the following output given the same f0, f1 and f2 instances

(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:可以使用一些调整来减少过多的空格,但仍然会打败替代品。

The above descriptionWithLocale:indent: could use some tweaking to reduce the excessive whitespace but it still beats the alternatives.

这篇关于调试器(或日志)中的NSDictionary-like漂亮打印的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆