Objective c 在NSDictionary中使用类作为键

Objective c 在NSDictionary中使用类作为键,objective-c,dictionary,Objective C,Dictionary,我正在编写一个上下文“工厂”,它将维护从某个转换器类继承的转换器/代理对象的字典。此类有一个方法: - (Class)classResponsibility 或者类似的,例如StringConverter类将实现以下方法: - (Class)classResponsibility { return [NSString class]; } 然后,为了将该转换器存储在字典中,我希望执行以下操作: [converters setValue:stringConverter forKey:[s

我正在编写一个上下文“工厂”,它将维护从某个转换器类继承的转换器/代理对象的字典。此类有一个方法:

- (Class)classResponsibility
或者类似的,例如StringConverter类将实现以下方法:

- (Class)classResponsibility {
    return [NSString class];
}
然后,为了将该转换器存储在字典中,我希望执行以下操作:

[converters setValue:stringConverter forKey:[stringConverter classResponsibility]];

但是编译器抱怨类型“Class”对于setValue:forKey:method的参数2是无效的参数类型。我本想避免将键设置为类的名称(“NSString”),但如果这是最好的解决方案,我将使用它。

-setValue:forKey:
被记录为将
NSString
作为第二个参数。您必须使用
NSStringFromClass()
NSClassFromString()
作为适配器。

我正在寻找setObject:forKey:方法,而不是setValue:forKey:。setObject:forKey:的方法签名接受(id)作为这两种参数类型,并且更适合。

您使用的是
setValue:forKey:
,它只接受
NSString
作为键。您应该改用
setObject:forKey:
。类对象(指向类对象的指针可以作为类型
class
传递)是一个成熟的Objective-C对象(类对象是其元类的实例,您可以在类对象上使用所有
NSObject
方法;阅读更多关于元类的信息),因此它们可以在使用对象的任何地方使用


字典键的另一个要求是它们支持复制(即,使用
copyWithZone:
方法。类对象支持此方法吗?事实上,它支持。NSObject类定义了一个类方法
+copyWithZone:
,其明确说明它“允许您使用类对象作为NSDictionary对象的键”.我想这就是你问题的答案。

我刚刚遇到了一个类似的情况,出现了完全相同的错误消息:

[tempDictionary setObject:someDictionary forKey:someClass];
我所做的就是在
someClass
中实现
NSCopying
协议:

- (id)copyWithZone:(NSZone *)zone
{
    id copy = [[[self class] allocWithZone:zone] init];
    [copy setId:[self id]];
    [copy setTitle:[self title]];
    return copy;
}
我认为发生的事情是,制作
someClass
的副本是为了用作键,但由于我的对象不知道如何复制自己(源自
NSObject
,它在超类中没有
copyWithZone
),所以它犹豫了

我发现我的方法是使用对象作为键。除非我已经实例化了对象,否则我会不断调用
allKeys
,或者只是在字典中枚举


[写完这篇文章后,我发现您希望将类存储为密钥。我将其保留在这里,因为如果我在搜索时找到了答案,我会节省很多时间。我当时没有找到类似的内容。]

您的另一个选项是使用
[NSValue valueWithNonretainedObject:yourObjectHere]
从字符串以外的其他对象构造键。我遇到了类似的问题,我想使用CoreData对象作为键,使用其他对象作为值。这个
NSValue
方法工作得很好,我相信这是它的初衷。要返回到原始值,只需调用
nonretainedObjectValue

虽然类对象在NSDictionary中是一个非常好的键,但值得一提的是NSMapTable,它是以NSDictionary为模型的,但它提供了更大的灵活性,可以将哪些类型的对象用作键和/或值,以支持弱引用和任意指针。

您可以将类用作
NSDictionary
's键如下:

@{
    (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,
};
甚至像这样:

@{
    (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,
};

setValue:forKey:的文档不是说在使用键值编码时,键值只能是一个对象吗?否则,它不能是任何实现NSCopying协议的对象,比如NSDictionary吗?非常有趣,谢谢。很遗憾,我已经走上了另一条路,但将来我会记得尝试一下。非常感谢我选择了替代方案,而不是在一百万个类中为我实现copyWithZone:)今天我偶然发现了这个问题,但让另一个类完美地工作了好几个月,我不明白为什么。有人会知道原因吗?“Model”是一个仅从NSObject派生的自定义类(不符合NSCoding)
静态NSMutableDictionary*singletonistance@实现SingletonModel+(void)initialize{singletonInstances=[[NSMutableDictionary alloc]initWithCapacity:10];}+(void)setSharedModel:(Model*)aModel{if(![singletonInstances objectForKey:[aModel class]]]{[singletonInstances setObject:aModel forKey:[aModel class]];}
@nobre:class对象可以用作键。请看这篇文章,它很好地讨论了实现
NSCopying
:Graham Lee:类确实实现了NSCopying。请参阅+copyWithZone:method的文档:从XCode 4.5开始,您需要首先强制转换它以不获得警告:[dictionary setObject:object forKey:(id)someClass];看到这个答案你知道键必须符合
NSCopying
的技术原因吗?@Drux我的猜测是,NSDictionary不希望保留其他人在不需要时发布的对象。如果NSDictionary保留该对象,其他人将其释放,则该对象仅由NSDictionary实例保留为键,并且当移除键的值时,该对象也将被移除。因此,复制使key对象仅对NSDictionary可用(如果查看
allKeys
方法,它还会返回key数组的副本)。@Drux我怀疑NSDictionary的实现对键设置后不会发生变异做出了一些优化假设。@Drux Frank部分正确,如果一个键的散列改变,它将中断查找。密钥必须是不可变的。这应该是新的首选解决方案iOS 6及更高版本。您可以将弱密钥用于NSMapTable类密钥吗?任何p