Object keys with NSMutableDictionary (Objective-C)

2019-04-07 02:47发布

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 explain 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.

4条回答
疯言疯语
2楼-- · 2019-04-07 02:58

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];
查看更多
Explosion°爆炸
3楼-- · 2019-04-07 02:59

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.

查看更多
叛逆
4楼-- · 2019-04-07 03:06

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.

查看更多
萌系小妹纸
5楼-- · 2019-04-07 03:20

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.

查看更多
登录 后发表回答