Object keys with NSMutableDictionary (Objective-C)

I want to store a bunch of key value pairs, and the key is my own object (ObjectA), which inherits from NSObject, and the value is int.
I am trying to use NSMutableDictionary. I understand that you can only store object types in a dictionary, so I have the following:

id value = [NSNumber numberWithInt:my_number]; [[self dictionary] setObject:value forKey:myObjectA]; 

Now it gives me an error saying

- [ObjectA copyWithZone:]: unrecognized selector sent to the instance

which is great, I understand that object keys must implement the NSCopying protocol. However, then I read that you can do this by wrapping your objects with NSValue.

Can someone explain how I will wrap my objects, and how can I find the value by key? Can I still use the dictionary objectForKey:myObjectA or do I need to wrap myObjectA with an NSValue while I'm looking too? Or should I embed NSCopying in my own class or use a string key instead?

I am looking for this simple and easy way to use a dictionary if I need to implement a string key and use setValue: forKey: instead, but I would prefer to use the object key if I can.

+7
source share
4 answers

Dictionary keys are always copied. Therefore, you just need to implement the NSCopying protocol for your class, which is only the copyWithZone: method.

In addition, you must implement the isEqual: method for your class.

Edit:. How to implement your copyWithZone: depends on a number of factors (main factor: deep or shallow). See Apple Object Copy Guide and this SO> answer .

+10
source

You can include id in NSValue with

 NSValue* value = [NSValue valueWithNonretainedObject:object]; ... id object_ = [value nonretainedObjectValue]; 

but you need to manage ownership outside the dictionary. It will be a mess. Better to accept NSCopying.


There is also a 4th option: use CFDictionary, which allows the object to be CFRetain / CFReleased only and not be copied.

 CFMutableDictionaryRef dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); ... CFDictionarySetValue(dict, myObjectA, value); ... CFRelease(dict); 

And if you are programming for Mac or iOS 6 and above, try NSMapTable.

 NSMapTable* dict = [[NSMapTable mapTableWithStrongToStrongObjects] retain]; ... [dict setObject:@"?" forKey:foo]; ... [dict release]; 
+6
source

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 select weak / strong attributes for keys and objects .

+2
source

You do not need to wrap your object with NSValue. What you have will work, except that you are missing a piece. For the myObjectA class, you need to accept the NSCopying protocol (see the docs for adding). After that, the added code that you posted above should work correctly.

You might want to use strings, but above your own key object. The key must be a string if key coding is used to access it at all. Thus, using a string will make life easier if you can use the key value anywhere you use the dictionary.

0
source

All Articles