6

我正在尝试合并两个 NSDictionaries:

NSDictionary *areaAttributes = [[area entity] attributesByName];
NSDictionary *gpsAttributes = [[gps entity] attributesByName];
NSMutableDictionary *combinedAttributes = [areaAttributes mutableCopy];
[combinedAttributes addEntriesFromDictionary:gpsAttributes];

但是得到以下错误:

Terminating app due to uncaught exception 'NSUnknownKeyException', reason: 'The key 'latitude' is not defined for this NSKnownKeysDictionary'

latitude是关键gpsAttributes

4

1 回答 1

11

这里的问题是你不是在处理普通的字典,而是在处理NSKnownKeysDictionary,这是 Apple 在 Cocoa 的各个部分中使用的一种未记录的类型。

如果您从 SDK 中转储 ObjC 类信息——或者,如果这听起来太吓人,请阅读其他人的版本——您会发现这实际上是 的子类NSMutableDictionary,而不仅仅是NSDictionary,所以它已经是可变的,所以你mutableCopy的不是必需的。

更重要的是,如果你阅读了NSCopyingNSMutableCopying协议是如何定义的,那么就没有什么需要mutableCopy返回与它的基类可变兼容的东西了。只是它是可变的,并且与它的基类不可变地兼容。这很烦人。

这里的答案是生成一个新的可变字典,并将两个 对象的键复制NSKnownKeysDictionary到其中:

NSDictionary *areaAttributes = [[area entity] attributesByName];
NSDictionary *gpsAttributes = [[gps entity] attributesByName];
NSMutableDictionary *combinedAttributes = [NSMutableDictionary dictionaryWithCapacity:20];
[combinedAttributes addEntriesFromDictionary:areaAttributes];
[combinedAttributes addEntriesFromDictionary:gpsAttributes];

(显然,如果您担心性能,您要么想要调整它20,要么从每个字典中获取键的数量并传递总数。但通常,这并不重要。)

您可能想知道为什么 Apple 会这样做。但如果你仔细想想,这是一件很方便的事情。你有一个对象,可以struct在某个库的内部像 C 一样使用,但在外部看起来就像NSDictionary. (类似的目的,例如,namedtuple在 Python 中。)返回它们的方法都被设计为 return NSDictionary, not NSMutableDictionary,所以没有人会知道他们有一组受限的键。当然,如果他们调用mutableCopy.

您可能还想知道如何提前知道这一点。好吧,你真的不能。要么记录对象的类型,要么编写异常处理程序并记录异常,要么让它崩溃并在故障转储中找到异常。或者,或者,您可以采取防御措施,并假设任何字典都可以给您一个无用mutableCopy且浅显的复制到您控制的类型的字典中。

于 2013-01-15T21:55:09.960 回答