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:
- (Class)classResponsibility
Or something similar, such that a StringConverter class would implement the method as:
- (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.
-
-setValue:forKey:is documented to take anNSStringas the second parameter. You'll have to useNSStringFromClass()andNSClassFromString()as adaptors.Jarret Hardie : You are right about Class being an objectJarret Hardie : Don't the docs for setValue:forKey: say that the key only has to be an object when using key-value coding? Otherwise, couldn't it be any object that implements NSCopying protocol, like NSDictionary? -
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.
Graham Lee : Classes don't implement NSCopying, so can't be used as the key in -setObject:forKey:. Really that parameter should be (id), I'm not sure why it's not. -
A class object (type Class) isn't actually an Objective-C object; it's a pointer to an opaque objc_class struct (you can see this in 'objc.h'). Because the keys to an NSDictionary have to be objects conforming to the NSCopying protocol, a Class isn't going to work for a key.
The simplest thing to do is call NSStringFromClass and use the name of the class as the key, as Graham Lee suggested.
The difference between setObject:forKey: and setValue:forKey: is that the latter is part of the key-value coding infrastructure. In general you'll probably want to prefer setObject:forKey: when dealing with NSMutableDictionary as it carries less semantic baggage and doesn't require your keys to be NSStrings (that's my opinion; in practice I suppose it's really more a matter of style).
-
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 insomeClass:- (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 fromNSObjectit didn't have acopyWithZonein 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
allKeysor 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.]
-
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. ThisNSValuemethod worked perfect and I believe was it's original intent. To get back to the original value just callnonretainedObjectValuecraig : Very interesting, thanks for that. I've unfortunately already gone down the other path, but in the future I will remember to give this a try.
0 comments:
Post a Comment