调试器(或日志)中的NSDictionary-like漂亮打印 [英] NSDictionary-like pretty-print in the debugger (or log)
问题描述
这段时间一直在欺骗我。如何解决在调试器中使用 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屋!