Re: Storing values in dictionary with their address as the key
Re: Storing values in dictionary with their address as the key
- Subject: Re: Storing values in dictionary with their address as the key
- From: Nathan Vander Wilt <email@hidden>
- Date: Tue, 29 Jul 2008 08:58:15 -0700
What about using CFDictionary ? You can create a dicitonary with a
callback that support address (NULL for example).
I'll echo this; it's a really handy technique that I use frequently
(you can even use integers as keys!).
WARNING: Just in case, there is a major warning here. You should
avoid NS/CF bridge when inserting/removing value in a dictionary as
the semantic is not the same. NSDictionary always try to copy the
key whatever the calback is (or at least did it the last time I try).
Right, -[NSDictionary setObject:forKey:] on a CFDictionary created
with a custom retain callback will invoke copyWithZone: before
calling your retain callback. Apple claims this is not a bug.
Getting/removing values with objectForKey:/removeObjectForKey:
should work, though; if it doesn't, I'd like to know.
Yes, accessing and removing keys should work fine. For immutable keys
(you weren't planning on changing a key behind NSDictionary's back
anyway, right) a copy is often just implemented as a retain. Since
toll-free bridged NSDictionary must provide CFDictionary retain/
release callbacks to work right on the Core Foundation side of things,
it must be copying the key, adding it to the array (where it is
retained by the callback), and then releasing it's local reference.
Take out steps one and three, which are equivalent to a retain
followed by a release, and nothing should change as far as object
accessing or removal.
While for new code in Leopard+ apps you might want to look into
NSMapTable with the flags Mike suggested, I just was dealing with
NSMutableDictionary's key copying off-list last night and didn't see
that suggestion. What I did is just added a category on
NSMutableDictionary:
@interface NSMutableDictionary (TLMutableDictionaryNoncopiedKeys)
- (void)setObject:(id)anObject forUncopiedKey:(id)aKey;
@end
@implementation NSMutableDictionary (TLMutableDictionaryNoncopiedKeys)
/* NSMutableDictionary copies its keys. When we use pointer-equality
for certain types' comparision,
this breaks those types' keys. Fortunately, CFMutableDictionary does
not assume NSString-ish keys,
and the copying behaviour is implemented within the -
[NSMutableDictionary addObject:forKey:]
method itself (see http://www.cocoabuilder.com/archive/message/cocoa/2008/4/2/203028
and links
for details).
If we just bridge to Core Foundation when adding keys, everything
else should work properly.
*/
- (void)setObject:(id)anObject forUncopiedKey:(id)aKey {
CFMutableDictionaryRef selfCF = (CFMutableDictionaryRef)self;
Boolean keyAlreadySet = CFDictionaryContainsKey(selfCF, aKey);
if (keyAlreadySet) {
CFDictionaryReplaceValue(selfCF, aKey, anObject);
}
else {
CFDictionaryAddValue(selfCF, aKey, anObject);
}
}
@end
Replacing this single method was enough for me, since in most cases in
my code where the "stringish" (that is, assuming copied keys will
still compare equal) behaviour is not desirable, I am creating an
empty dictionary and populating it with just that one method.
Otherwise, many other methods (especially NSDictionary's initializers
and convenience initializers) would all need "uncopiedKey" overrides,
and some of these could theoretically end up being much less efficient
than the methods they replaced. However, if you can't use just the
above method to insert keys, then other solutions like CFDictionary
and NSMapTable (especially) might not work much better for you
anyway...so this seems like a pretty decent solution for many cases.
hope this helps,
-natevw
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden