这一直困扰着我。如何使用po foo
(或通过NSLog
)在调试器中转储对象时,如何抵消发生的丑陋转义。我尝试了很多方法来实现-description
或-debugDescription
无济于事。
鉴于这个简单的课程
@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
以来我还缺少其他一些技巧NSDictionary* d0 = @{ @"value": @0, @"next": NSNull.null };
NSDictionary* d1 = @{ @"value": @1, @"next": d0 };
NSDictionary* d2 = @{ @"value": @2, @"next": d1 };
保持缩进并避免逃避地狱
(lldb) po d2
{
next = {
next = {
next = "<null>";
value = 0;
};
value = 1;
};
value = 2;
}
更新
切换到-debugDescription
并简单地转发到词典
@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;
}
答案 0 :(得分:4)
使用NSContainers-PrettyPrint并谨慎read docs。
经过更多搜索后,我发现了descriptionWithLocale:indent:
方法。如上所述,我应该能够在我自己的类中实现它,以实现所需的漂亮打印格式。但是,经过一些尝试失败后我找到了similar SO question。事实证明descriptionWithLocale:indent:
仅在您因为“安全问题”而继承基础容器类时才有效。
对这种方法不满意我继续挖掘并找到了这个radar,但也是NSContainers-PrettyPrint中的解决方案。经过一些反复试验后,我得到了很好的工作。 (它不在CocoaPods上,所以你必须手动添加它。)
添加NSContainers-PrettyPrint后,您可能也需要JRSwizzle。然后在DEBUG目标预处理器宏中定义DEBUGPRINT_ALL
和DEBUGPRINT_SWIZZLE
。最后,您可以根据fs_* helpers和best practices实施descriptionWithLocale:indent:
方法。
使用我问题中的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:
可以使用一些调整来减少过多的空白,但它仍然可以替代它。
答案 1 :(得分:2)
类似的问题(NSDictionary description
formatting problem — treats structure like char data)表明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中使用它似乎很好。