我正在编写一个上下文“工厂”,它将维护一个继承自某些Converter类的转换器/动作对象的字典。这个类有一个方法:
- (Class)classResponsibility
或类似的东西,这样StringConverter类将实现该方法:
- (Class)classResponsibility {
return [NSString class];
}
然后将该转换器存储在字典中,我曾希望做类似的事情:
[converters setValue:stringConverter forKey:[stringConverter classResponsibility]];
但是编译器抱怨类型“Class”是setValue:forKey:方法的参数2的无效参数类型。我本来想避免将密钥设置为类的名称(“NSString”),但如果这是最好的解决方案而不是我将使用它。
答案 0 :(得分:98)
您正在使用仅setValue:forKey:
作为键的NSString
。你应该使用setObject:forKey:
代替。类对象(指向类对象的指针可以作为类型Class
传递)是一个成熟的Objective-C对象(类对象是其元类的一个实例,你可以使用所有{{1类对象上的方法;阅读有关元类here)的更多信息,因此可以在任何使用对象的地方使用它们。
字典键的另一个要求是它们支持复制(即使用NSObject
方法。类对象是否支持此方法?事实上,它确实如此.NSObject类定义了一个类方法< / em> copyWithZone:
,其documentation明确表示它“允许您使用类对象作为NSDictionary对象的键”。我认为这是您问题的答案。
答案 1 :(得分:30)
您的另一个选择是使用[NSValue valueWithNonretainedObject:yourObjectHere]
从字符串以外的其他内容构造密钥。我遇到了类似的问题,我想使用CoreData对象作为键,其他东西作为值。这种NSValue
方法非常完美,我相信这是最初的意图。要返回原始值,只需拨打nonretainedObjectValue
答案 2 :(得分:4)
-setValue:forKey:
以NSString
作为第二个参数。您必须使用NSStringFromClass()
和NSClassFromString()
作为适配器。
答案 3 :(得分:3)
我正在寻找 setObject:forKey :方法而不是setValue:forKey:。 setObject:forKey的方法签名:接受(id)作为两种参数类型,并且更适合。
答案 4 :(得分:3)
虽然Class对象在NSDictionary中是一个非常好的键,但值得一提的是NSMapTable,它是以NSDictionary为模型的,但它提供了更多的灵活性,可以使哪种对象适合用作键和/或值,{{ 3}}支持弱引用和任意指针。
答案 5 :(得分:1)
我刚刚遇到了类似的情况,并出现了完全相同的错误消息:
[tempDictionary setObject:someDictionary forKey:someClass];
我所做的就是在NSCopying
中实施someClass
协议:
- (id)copyWithZone:(NSZone *)zone
{
id copy = [[[self class] allocWithZone:zone] init];
[copy setId:[self id]];
[copy setTitle:[self title]];
return copy;
}
我认为发生的事情是someClass
的副本正在被用作关键,但由于我的对象不知道如何复制自己(源自NSObject
我用我的方法发现的一件事是它使用一个对象作为关键。除非我已经实例化了对象,否则我会不断调用allKeys
或者只是枚举字典。
[写完之后,我发现你想把这个类存储为密钥等。我把它留在那里是因为如果我在搜索时找到答案,我会节省很多时间。我当时没有找到这样的东西。]
答案 6 :(得分:0)
您可以将这些类用作NSDictionary
的键,如下所示:
@{
(id)[MyClass1 class] : @1,
(id)[MyClass2 class] : @2,
(id)[MyClass3 class] : @3,
(id)[MyClass4 class] : @4,
};
或者甚至喜欢这样:
@{
MyClass1.self : @1,
MyClass2.self : @2,
MyClass3.self : @3,
MyClass4.self : @4,
};