I want to store a bunch of key value pairs, with the key being my own object (ObjectA) that inherits from NSObject, and the value being an int.
I am trying to use an NSMutableDictionary. I understand that you can only store object types in the dictionary, so I have the following:id value = [NSNumber numberWithInt:my_number];
[[self dictionary] setObject:value forKey:myObjectA];
Now that gives me an error, saying
-[ObjectA copyWithZone:]: unrecognized selector sent to instance
which is fine, I understand that object keys need to implement the NSCopying protocol. However I then read that you can do this by wrapping your objects using NSValue.
Can someone please expl开发者_如何学Goain how I would wrap my objects, and how I can then find the value by the key? Am I still able to use dictionary objectForKey:myObjectA
or do I have to wrap myObjectA with an NSValue object while I'm searching as well? Or should I be implementing NSCopying on my custom class, or using a string key instead?
I am looking for this simplest and easiest way to use a dictionary, if I have to I'll implement a string key and use setValue:forKey: instead but I'd rather use the object key if I can.
Dictionary keys are always copied. So you simply need to implement the NSCopying protocol for your class, which is just the copyWithZone:
method.
Additionally you should implement the isEqual:
method for your class.
Edit: How to implement your copyWithZone:
depends on a number of factors (main factor: deep vs. shallow copy). See Apple's Implementing Object Copy guide and this SO answer.
You could turn an id
into an NSValue with:
NSValue* value = [NSValue valueWithNonretainedObject:object];
...
id object_ = [value nonretainedObjectValue];
but you need to manage the ownership outside of the dictionary. This is going to be a mess. It's better to adopt NSCopying.
There is also a 4th option: use a CFDictionary, which allows the object only can be CFRetain/CFReleased, not copied.
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks
);
...
CFDictionarySetValue(dict, myObjectA, value);
...
CFRelease(dict);
And if you're programming for Mac or iOS 6 and above, try NSMapTable.
NSMapTable* dict = [[NSMapTable mapTableWithStrongToStrongObjects] retain];
...
[dict setObject:@"?" forKey:foo];
...
[dict release];
In iOS 6 you can use NSMapTable (https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/NSMapTable_class/Reference/NSMapTable.html), which allows you to chose weak/strong attributes for the keys and objects.
You don't need to wrap your object using NSValue. What you have will work except you're missing a piece. For myObjectA's class you need to adopt the NSCopying protocol (see the docs for what to add). Once that's added the code you posted above should work correctly.
You might want to consider using strings though over your own object for the key. The key is required to be a string if key-value coding is going to be used to access it at all. So using a string will make life easier if you can take advantage of key-value coding anywhere you're using the dictionary.
精彩评论