NSDictionary`描述`格式化问题 - 将结构视为char数据

时间:2023-01-14 15:33:35

I've got a custom class (which resembles an NSArray in concept and, hopefully, formatted appearance) which has a description formatter.

我有一个自定义类(类似于NSArray的概念,希望是格式化​​的外观),它有一个描述格式化程序。

When the output of the formatter is printed (NSLog) by itself it looks fine, but when it's included as an element of an NSDictionary description the NSDictionary formatter seems to decide that it's a character string, not a structure definition, encloses it in quotes, and escapes all of the control characters in the string.

当格式化程序的输出本身打印(NSLog)时它看起来很好,但当它作为NSDictionary描述的元素包含时,NSDictionary格式化程序似乎决定它是一个字符串,而不是结构定义,用引号括起来,并转义字符串中的所有控制字符。

It doesn't do this for a standard NSArray, of course, so I'm wondering how it decides to treat the string one way vs the other.

当然,对于标准的NSArray,它不会这样做,所以我想知道它是如何决定以一种方式对待另一种方式来处理字符串的。

Eg, rather than having output that looks like:

例如,而不是具有如下输出:

theChildren = (
                  {
                      "@meta.type" = "ns3:location";
                      "childNumber" = 0;
                      ...

It looks like:

看起来像:

theChildren = "( \n\t\t {\n\t  \"@meta.type\" = \"ns3:location\";\n\t   \"childNumber\" = 0;
...

Can anyone suggest a way to alter this behavior?

任何人都可以提出改变这种行为的方法吗?

FWIW, I accumulate the description string (with data consisting primarily of the results from calls to NSDictionary description) in an NSMutableString, then do NSString stringFromString at the exit (though I don't know that that does anything).

FWIW,我在NSMutableString中累积描述字符串(主要由调用NSDictionary描述的结果组成的数据),然后在出口处执行NSString stringFromString(虽然我不知道它做了什么)。

Added

I think I found the answer (haven't checked yet) buried in the NSDictionary writeup:

我想我找到了NSDictionary写入中的答案(尚未检查):

Discussion

The returned NSString object contains the string representations of each of the dictionary’s entries. descriptionWithLocale:indent: obtains the string representation of a given key or value as follows:

返回的NSString对象包含每个字典条目的字符串表示形式。 descriptionWithLocale:indent:获取给定键或值的字符串表示形式,如下所示:

If the object is an NSString object, it is used as is.

If the object responds to descriptionWithLocale:indent:, that

method is invoked to obtain the object’s string representation.

调用方法以获取对象的字符串表示形式。

If the object responds to descriptionWithLocale:, that method is

invoked to obtain the object’s string representation.

调用以获取对象的字符串表示形式。

If none of the above conditions is met, the object’s string

representation is obtained by invoking its description method.

表示是通过调用其描述方法获得的。

Update

Well, turns out they lie. I implemented descriptionWithLocale:indent: and it never gets called.

好吧,事实证明他们撒谎。我实现了descriptionWithLocale:indent:它永远不会被调用。

Update 9/23

Interestingly, if I make my class a subclass of NSArray then NSDictionary calls descriptionWithLocale:indent: and it formats correctly. Sounds like NSDictionary is "cheating" and testing isKindOfClass rather than respondsToSelector, or else is just prejudiced against non-NS stuff.

有趣的是,如果我使我的类成为NSArray的子​​类,那么NSDictionary会调用descriptionWithLocale:indent:并且它正确格式化。听起来像NSDictionary是“作弊”和测试isKindOfClass而不是respondsToSelector,否则只是对非NS的东西有偏见。

It's kind of ugly to have to subclass NSArray, though, in terms of acquiring a lot of behaviors I don't want to mimic, and carrying extra unused data.

然而,在获取许多我不想模仿的行为以及携带额外的未使用数据方面,必须继承NSArray是一种丑陋。

Etc

Another option is to convert the escaped string back to its original. This takes a 31-line procedure to handle the basics (\n, \t, \", and \\). The up-side is that I don't need to subclass NSArray. The main downside is that this routine must be inserted in any NSLog call that could display my class. Another minor downside is that the escaped strings were wrappered with quote characters I can't eliminate, but that's hardly noticeable.

另一种选择是将转义字符串转换回原始字符串。这需要一个31行程序来处理基础知识(\ n,\ t,\ t,\ t和\\)。最重要的是我不需要子类化NSArray。主要的缺点是这个例程必须是插入任何可以显示我的类的NSLog调用。另一个小的缺点是转义的字符串包含了我无法消除的引号字符,但这几乎不可察觉。

Got it #ifdefed for now -- not sure which I'll pick.

现在得到#ifdefed - 不确定我会选择哪个。

2 个解决方案

#1


5  

This is a wonderful security-related "feature" that was introduced in OS X 10.5+ version of syslog().

这是OS X 10.5+版本的syslog()中引入的一个与安全相关的精彩“功能”。

As explained by an Apple engineer in this post: Who broke NSLog on Leopard?,

正如一位苹果工程师在这篇文章中解释的那样:谁在Leopard上打破了NSLog?

That's the behavior of syslog(). From the man page:

这是syslog()的行为。从手册页:

Newlines and other non-printable characters embedded in the message string are printed in an alternate format. This prevents someone from using non-printable characters to construct misleading log messages in an output file. Newlines are printed as "\n", tabs are printed as "\t". Other control characters are printed using a caret ("^") representation, for example "^M" for carriage return.

嵌入在消息字符串中的换行符和其他不可打印字符以替代格式打印。这可以防止有人使用不可打印的字符在输出文件中构造误导性日志消息。换行符打印为“\ n”,选项卡打印为“\ t”。使用插入符号(“^”)表示打印其他控制字符,例如“^ M”用于回车。

The ASL subsystem, which NSLog() writes to, does the same (at least in Leopard). Writing the XML to a file is a reasonable alternative.

NSLog()写入的ASL子系统也是如此(至少在Leopard中)。将XML写入文件是一种合理的选择。

Chris Kane Cocoa Frameworks, Apple

Chris Kane Cocoa Frameworks,Apple

See man syslog for more info.

有关详细信息,请参阅man syslog。

#2


2  

There's no real answer to this question (the "security feature" of OS X doesn't appear to affect iOS console writes), but there are these two work-arounds:

这个问题没有真正的答案(OS X的“安全功能”似乎不会影响iOS控制台写入),但有两种解决方法:

#1: Interestingly, if I make my class a subclass of NSArray then NSDictionary calls descriptionWithLocale:indent: and it formats correctly. Sounds like NSDictionary is "cheating" and testing isKindOfClass rather than respondsToSelector, or else is just prejudiced against non-NS stuff.

#1:有趣的是,如果我让我的类成为NSArray的子​​类,那么NSDictionary会调用descriptionWithLocale:indent:并且它正确格式化。听起来像NSDictionary是“作弊”和测试isKindOfClass而不是respondsToSelector,否则只是对非NS的东西有偏见。

It's kind of ugly to have to subclass NSArray, though, in terms of acquiring a lot of behaviors I don't want to mimic, and carrying extra unused data. Etc

然而,在获取许多我不想模仿的行为以及携带额外的未使用数据方面,必须继承NSArray是一种丑陋。等等

#2: Another option is to convert the escaped string back to its original. This takes a 31-line procedure to handle the basics (\n, \t, \", and \). The up-side is that I don't need to subclass NSArray. The main downside is that this routine must be inserted in any NSLog call that could display my class. Another minor downside is that the escaped strings were wrappered with quote characters I can't eliminate, but that's hardly noticeable.

#2:另一种选择是将转义字符串转换回原始字符串。这需要一个31行程序来处理基础知识(\ n,\ t,\ t \,和\)。最重要的是我不需要子类化NSArray。主要缺点是必须插入此例程在任何可以显示我的类的NSLog调用中。另一个小的缺点是转义的字符串包含了我无法消除的引号字符,但这几乎不可察觉。

(Accepted this answer, even though it's not the "real" answer, because my accepted % would suffer otherwise. I ask too many difficult questions, I guess.)

(接受这个答案,即使这不是“真正的”答案,因为我接受的%会受到影响。我想我会问太多难题。)

#1


5  

This is a wonderful security-related "feature" that was introduced in OS X 10.5+ version of syslog().

这是OS X 10.5+版本的syslog()中引入的一个与安全相关的精彩“功能”。

As explained by an Apple engineer in this post: Who broke NSLog on Leopard?,

正如一位苹果工程师在这篇文章中解释的那样:谁在Leopard上打破了NSLog?

That's the behavior of syslog(). From the man page:

这是syslog()的行为。从手册页:

Newlines and other non-printable characters embedded in the message string are printed in an alternate format. This prevents someone from using non-printable characters to construct misleading log messages in an output file. Newlines are printed as "\n", tabs are printed as "\t". Other control characters are printed using a caret ("^") representation, for example "^M" for carriage return.

嵌入在消息字符串中的换行符和其他不可打印字符以替代格式打印。这可以防止有人使用不可打印的字符在输出文件中构造误导性日志消息。换行符打印为“\ n”,选项卡打印为“\ t”。使用插入符号(“^”)表示打印其他控制字符,例如“^ M”用于回车。

The ASL subsystem, which NSLog() writes to, does the same (at least in Leopard). Writing the XML to a file is a reasonable alternative.

NSLog()写入的ASL子系统也是如此(至少在Leopard中)。将XML写入文件是一种合理的选择。

Chris Kane Cocoa Frameworks, Apple

Chris Kane Cocoa Frameworks,Apple

See man syslog for more info.

有关详细信息,请参阅man syslog。

#2


2  

There's no real answer to this question (the "security feature" of OS X doesn't appear to affect iOS console writes), but there are these two work-arounds:

这个问题没有真正的答案(OS X的“安全功能”似乎不会影响iOS控制台写入),但有两种解决方法:

#1: Interestingly, if I make my class a subclass of NSArray then NSDictionary calls descriptionWithLocale:indent: and it formats correctly. Sounds like NSDictionary is "cheating" and testing isKindOfClass rather than respondsToSelector, or else is just prejudiced against non-NS stuff.

#1:有趣的是,如果我让我的类成为NSArray的子​​类,那么NSDictionary会调用descriptionWithLocale:indent:并且它正确格式化。听起来像NSDictionary是“作弊”和测试isKindOfClass而不是respondsToSelector,否则只是对非NS的东西有偏见。

It's kind of ugly to have to subclass NSArray, though, in terms of acquiring a lot of behaviors I don't want to mimic, and carrying extra unused data. Etc

然而,在获取许多我不想模仿的行为以及携带额外的未使用数据方面,必须继承NSArray是一种丑陋。等等

#2: Another option is to convert the escaped string back to its original. This takes a 31-line procedure to handle the basics (\n, \t, \", and \). The up-side is that I don't need to subclass NSArray. The main downside is that this routine must be inserted in any NSLog call that could display my class. Another minor downside is that the escaped strings were wrappered with quote characters I can't eliminate, but that's hardly noticeable.

#2:另一种选择是将转义字符串转换回原始字符串。这需要一个31行程序来处理基础知识(\ n,\ t,\ t \,和\)。最重要的是我不需要子类化NSArray。主要缺点是必须插入此例程在任何可以显示我的类的NSLog调用中。另一个小的缺点是转义的字符串包含了我无法消除的引号字符,但这几乎不可察觉。

(Accepted this answer, even though it's not the "real" answer, because my accepted % would suffer otherwise. I ask too many difficult questions, I guess.)

(接受这个答案,即使这不是“真正的”答案,因为我接受的%会受到影响。我想我会问太多难题。)