NSDictionary `description` 格式问题——将结构视为字符数据

发布于 2024-12-06 05:04:02 字数 1923 浏览 0 评论 0原文

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

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

当然,它不会对标准 NSArray 执行此操作,所以我想知道它如何决定以一种方式处理字符串而不是另一种方式。

例如,而不是输出看起来像:

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

它看起来像:

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

任何人都可以建议一种方法来改变这种行为吗?

FWIW,我在 NSMutableString 中累积描述字符串(数据主要由调用 NSDictionary description 的结果组成),然后在退出时执行 NSString stringFromString (尽管我不这样做)不知道那有什么作用)。

添加

我想我找到了隐藏在 NSDictionary 文章中的答案(尚未检查):

讨论

返回的 NSString 对象包含以下字符串表示形式 字典的每个条目。描述与区域设置:缩进: 获取给定键或值的字符串表示形式,如下所示:

如果该对象是 NSString 对象,则按原样使用。

如果对象响应descriptionWithLocale:indent:,则

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

如果对象响应descriptionWithLocale:,则该方法是

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

如果以上条件都不满足,则对象的字符串

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

更新

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

9/23 更新

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

不过,就获取许多我不想模仿的行为以及携带额外未使用的数据而言,必须对 NSArray 进行子类化有点丑陋。

等等

另一种选择是将转义字符串转换回原始字符串。这需要一个 31 行的过程来处理基础知识(\n\t\"\\

它#ifdefed——不确定我会选择哪个。

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

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.

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.

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).

Added

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

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:

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.

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.

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

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

会发光的星星闪亮亮i 2024-12-13 05:04:02

这是 OS X 10.5+ 版本的 syslog() 中引入的一项出色的安全相关“功能”。

正如苹果工程师在这篇文章中所解释的: 谁在 Leopard 上破坏了 NSLog?,

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

<块引用>
<块引用>

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


NSLog() 写入的 ASL 子系统执行相同的操作(至少在
豹)。将 XML 写入文件是一个合理的替代方案。

Chris Kane Cocoa 框架,Apple

请参阅 < code>man syslog 了解更多信息。

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

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

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

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.

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

Chris Kane Cocoa Frameworks, Apple

See man syslog for more info.

木有鱼丸 2024-12-13 05:04:02

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

#1:有趣的是,如果我使我的类成为 NSArray 的子类,然后 NSDictionary 调用 descriptionWithLocale:indent: 并且其格式正确。听起来 NSDictionary 是“作弊”,测试 isKindOfClass 而不是 respondsToSelector,否则只是对非 NS 的东西有偏见。

不过,就获取许多我不想模仿的行为以及携带额外未使用的数据而言,必须对 NSArray 进行子类化有点丑陋。
等等

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

(接受这个答案,即使它不是“真正的”答案,因为我想,否则我接受的%会受到影响。)

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:

#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.

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

#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.

(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.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文