objective-c 在 NSDictionary 中使用类作为键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/730076/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 21:22:51  来源:igfitidea点击:

Using class as key in NSDictionary

objective-cdictionary

提问by Craig Otis

I'm writing a contextual "factory" that will maintain a dictionary of converter/acting objects which inherit from some Converter class. This class has a method:

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

- (Class)classResponsibility

Or something similar, such that a StringConverter class would implement the method as:

或类似的东西,例如 StringConverter 类将实现该方法:

- (Class)classResponsibility {
    return [NSString class];
}

Then to store that converter in the dictionary, I had hoped on doing something like:

然后将该转换器存储在字典中,我曾希望做这样的事情:

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

But the compiler complains that the type "Class" is an invalid parameter type for argument 2 of the setValue:forKey: method. I had wanted to avoid setting the key as the Class's name ("NSString"), but if that's the best solution than I'll go with it.

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

回答by Skirwan

You're using setValue:forKey:which only takes NSStrings as keys. you should be using setObject:forKey:instead. A class object (pointers to class objects can be passed as type Class) is a full-fledged Objective-C object (a class object is an instance of its meta-class, and you can use all the NSObjectmethods on a class object; read more about meta-classes here), so they can be used anywhere objects are used.

您正在使用setValue:forKey:which 只将NSStrings 作为键。你应该setObject:forKey:改用。类对象(指向类对象的指针可以作为 type 传递Class)是一个成熟的 Objective-C 对象(类对象是其元类的实例,您可以使用NSObject类对象上的所有方法;阅读更多关于这里的元类),因此它们可以在任何使用对象的地方使用。

Another requirement for keys of a dictionary is that they support copying (i.e. have the copyWithZone:method. Do class objects support this method? In fact, it does. The NSObject class defines a class method+copyWithZone:, whose documentationexplicitly says that it "lets you use a class object as a key to an NSDictionary object". I think that's the answer to your question.

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

回答by Sean

Your other option is to use [NSValue valueWithNonretainedObject:yourObjectHere]to construct the key from something other than a string. I ran into a similar problem and I wanted to use a CoreData object as the key and something else as the value. This NSValuemethod worked perfect and I believe was it's original intent. To get back to the original value just call nonretainedObjectValue

您的另一个选择是用于[NSValue valueWithNonretainedObject:yourObjectHere]从字符串以外的内容构造密钥。我遇到了类似的问题,我想使用 CoreData 对象作为键,使用其他对象作为值。这种NSValue方法效果很好,我相信这是它的初衷。要恢复到原始值,只需调用nonretainedObjectValue

回答by Sean

-setValue:forKey:is documented to take an NSStringas the second parameter. You'll have to use NSStringFromClass()and NSClassFromString()as adaptors.

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

回答by Craig Otis

I was looking for the setObject:forKey: method instead of setValue:forKey:. The method signature for setObject:forKey: accepts (id) as both parameter types, and is much better suited.

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

回答by Tom M

While a Class object makes a perfectly good key in an NSDictionary, it's worth mentioning NSMapTable, which is modeled after NSDictionary, but provides more flexibility as to what kind of objects are suitable for use as keys and/or values, documentedto support weak references and arbitrary pointers.

虽然 Class 对象在 NSDictionary 中是一个非常好的键,但值得一提的是 NSMapTable,它是在 NSDictionary 之后建模的,但是对于适合用作键和/或值的对象类型提供了更大的灵活性,并记录以支持弱引用和任意指针。

回答by bbrown

I just had a similar situation crop up with the exact same error message:

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

[tempDictionary setObject:someDictionary forKey:someClass];

All I did was implement the NSCopyingprotocol in someClass:

我所做的只是NSCopyingsomeClass以下位置实现协议:

- (id)copyWithZone:(NSZone *)zone
{
    id copy = [[[self class] allocWithZone:zone] init];
    [copy setId:[self id]];
    [copy setTitle:[self title]];
    return copy;
}

I think what was happening was that a copy of someClasswas being made in order to be used as the key, but since my object didn't know how to copy itself (deriving from NSObjectit didn't have a copyWithZonein the superclass) it balked.

我认为正在发生的事情是someClass为了用作密钥而制作了一个副本,但是由于我的对象不知道如何复制自己(从NSObject它派生copyWithZone的超类中没有 a ),它犹豫了。

One thing I've found with my approach is that it's use an object as a key. Unless I already have the object instantiated, I'm constantly calling allKeysor just otherwise enumerating over the dictionary.

我在我的方法中发现的一件事是它使用对象作为键。除非我已经实例化了对象,allKeys否则我会不断调用或以其他方式枚举字典。

[After writing this, I see that you want to store the class as such as the key. I'm leaving this out there because I would have saved a lot of time if I had found my answer when I was searching SO. I didn't find anything like this then.]

[写完这篇之后,我看到你想要将类存储为密钥。我把这个留在那里,因为如果我在搜索 SO 时找到了我的答案,我会节省很多时间。我当时没有找到类似的东西。]

回答by k06a

You can use classes as NSDictionary's keys like this:

您可以NSDictionary像这样使用 classes as的键:

@{
    (id)[MyClass1 class] : @1,
    (id)[MyClass2 class] : @2,
    (id)[MyClass3 class] : @3,
    (id)[MyClass4 class] : @4,
};

Or even like this:

或者甚至像这样:

@{
    MyClass1.self : @1,
    MyClass2.self : @2,
    MyClass3.self : @3,
    MyClass4.self : @4,
};