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:
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, documented to support weak references and arbitrary pointers.
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 NSCopying
protocol in someClass
:
- (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 someClass
was being made in order to be used as the key, but since my object didn't know how to copy itself (deriving from NSObject
it didn't have a copyWithZone
in the superclass) it balked.
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 allKeys
or just otherwise enumerating over the dictionary.
[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.]
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.
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 NSValue
method worked perfect and I believe was it's original intent. To get back to the original value just call nonretainedObjectValue
You're using setValue:forKey:
which only takes NSString
s 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 NSObject
methods on a class object; read more about meta-classes here), so they can be used anywhere objects are used.
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 documentation explicitly 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.
You can use classes as NSDictionary
's keys like this:
@{
(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,
};