我有一个名为Settings的对象,它继承自NSMutableDictionary
。当我尝试使用
Settings *settings = [[Settings alloc] initWithContentsOfFile: @"someFile"]
它返回NSCFDictionary
类型的对象。因此,它无法识别我的其他方法。例如,当我调用选择器“save”时,它对象:
[NSCFDictionary save]: unrecognized selector sent to instance 0x524bc0
当然,当我使用花园种类
初始化时,它没关系Settings *settings = [[Settings alloc] init]
我试图再次将其强制转换为设置,但这不起作用。这看起来很简单 - 我错过了什么?
由于
答案 0 :(得分:18)
NSDictionary是一个类集群。这意味着从其init方法返回的值不是严格意义上的NSDictionary,而是实现实际功能的子类。几乎在所有情况下,最好为您的类提供一个NSDictionary作为实例变量,或者只是在NSDictionary上定义一个类别。
答案 1 :(得分:16)
Chuck对于NSDictionary(和Dave,扩展名,关于NSArray / Set / String)和类集群是正确的。可能性是-[NSDictionary initWithContentsOfFile:]
调用与-init
不同的初始化程序,这就是为什么它为NSMutableDictionary的另一个子类交换分配的Settings
实例。 (从文件读取时的初始化操作可能会选择NSDictionary的特定已知子类,该子类可以很好地从文件中加载等。)
我会回应Chuck的指导,使用组合或类别而不是NSDictionary的继承,几乎总是。您很可能以更简单的方式完成类别操作,并在此过程中减少潜在的错误。在决定继承之前,请考虑自己警告。
话虽如此,NSDictionary和NSMutableDictionary都被设计为支持子类化,并且在极少数情况下这是正确的事情。在尝试之前,请仔细考虑它。如果您发现它是您设计的正确选择,请按照以下要求了解并执行以下操作:
-count
-objectForKey:
-keyEnumerator
-initWithObjects:forKeys:count
:(指定的初始化程序)-setObject:forKey:
-removeObjectForKey:
classForKeyedArchiver
和replacementObjectForKeyedArchiver:
(来自NSObject的两种实例方法) - 它们可以完全改变您的课程响应方式,并且您经常无意中继承来自NS(Mutable)Dictionary的一些奇怪的行为。 (您可以通过在它们上设置断点来验证它们是否是罪魁祸首,或者实现它们以调用超级并打破您自己的代码。)我在我自己的NSMutableDictionary子类中实现了许多这些点。您可以check it out并使用代码,但可能对您有所帮助。一个特别帮助我(并且可能是你的问题的解决方案)的一个是重载指定的初始化程序,该程序目前没有记录(雷达#7046209)。
要记住的是,尽管这些子弹涵盖了最常见的用途,但总会有边缘情况和不常见的功能需要考虑。例如,-isEqual:
和-hash
用于测试相等性等。
答案 2 :(得分:3)
如果您确实阅读了NSDictionary的规范(我知道一个草皮动作),您将找到一个名为“Subclassing Notes”的部分。在其中,您将阅读:
如果您确实需要继承NSDictionary,则需要考虑 由类集群表示 - 因此有几个 方法基于概念的原始方法:
initWithObjects:forKeys: count objectForKey: keyEnumerator
在子类中,您必须覆盖所有这些方法。
答案 3 :(得分:1)
从https://stackoverflow.com/a/1191351/467588开始,这就是我为使NSDictionary的子类工作所做的工作。我只是将NSDictionary声明为我的类的实例变量,并添加一些更多必需的方法。我不知道该怎么称呼他们。
我在此处发布了我的代码示例https://stackoverflow.com/a/10993594/467588。
答案 4 :(得分:1)
这个问题非常陈旧,而且由于大部分答案都已发布,Apple已推出object subscripting,这样您就可以让自己的课程表现得更像NSMutableArray
或NSMutableDictionary
。这比上面讨论的替代方案简单。
至少,您必须覆盖这些方法:
//Array-style
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
//Dictionary-style
- (id)objectForKeyedSubscript:(id <NSCopying>)key;
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;
这是一个很好的tutorial如何做到这一点。