NSManagedObject as NSDictionary key?
cocoa, core-data, nscopying, nsdictionary
Solution
There are four options:
- Use a different object as the dictionary key instead, and lookup from that. `[object objectID]` or `+[NSValue valueWithNonretainedObject:]` seem the most obvious
- Use `CFDictionaryCreateMutable()` to create a dictionary with retained keys, rather than copied, instead, and then call `CFDictionarySetValue()` to store the objects
- On OS X or iOS6+, `[NSMapTable mapTableWithStrongToStrongObjects]` gives you a purely Objective-C equivalent to `CFMutableDictionary`
- Implement `NSCopying` for your managed object subclass, such that it returns self (with a bumped reference count if you're not using ARC)
Notes
`+valueWithNonretainedObject:` is pretty dangerous, since it's possible to be left with a dangling pointer; likely best to avoid.
Storing object IDs is fine, apart from the fact that new objects start out life with a temporary ID. That ID then changes to a permanent one when the context is saved to disk (or `-obtainPermanentIDsForObjects:…` is called). Your mapping code needs to be smart enough to handle this unless it can guarantee that all incoming objects already have a permanent ID.
Implementing `NSCopying` like this feels a bit icky, but should work just fine. As it happens, this is exactly the approach `NSURLSessionTask` takes, I presume for dictionary friendliness.
Prior to OS X 10.8 Mountain Lion, it used to be possible to create a regular `NSMutableDictionary` and then call `CFDictionarySetValue()` for it. That's no longer the case though; new dictionaries now have proper copy callbacks specified down at the CF level, rather than purely being a feature of `NSMutableDictionary`.
Problem
In my app, I have a `NSDictionary` whose keys should be instances of a subclass of `NSManagedObject`. The problem, however, is that `NSManagedObject` does not implement the `NSCopying` protocol which means that no Core Data objects / instances of `NSManagedObject` can be used as dictionary keys even though the `-[hash]` method works fine for them. Was should I do?