Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a clean way to use pointers (ids) as keys in an NSMutableDictionary?

I'm using NSMutableDictionary to store what is effectively a descriptor for certain classes, because I'd rather not waste the memory of adding the descriptor to every instance of classes, since only a very small subset of 1000s of objects will have the descriptor.

Unfortunately, given:

MyClass* p = [MyClass thingy];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSString* description = @"blah"; //does this work? If not I'm just simplifying for this example.
[dict setObject:description forKey:p]; // BZZZZT a copy of p is made using NSCopying

MyClass* found = [dict objectForKey:p]; //returns nil, as p becomes a different copy.

So that doesn't work.

I can hack it by passing in an NSNumber like so:

[dict setObject:description forKey:[NSNumber numberWithInt:(int)p]]; // this is cool

But that's not only ugly, but error prone since it is nonstandard.

With that in mind, is there a clean way to do this?

like image 811
Charles Randall Avatar asked Apr 27 '11 04:04

Charles Randall


3 Answers

NSValue confirms NSCopying as per NSValue Class Reference. So you can use an instance of NSValue as a key.

Use +valueWithPointer: to wrap the pointer value up.

NSString* foo = @"foo";
id bar = @"bar";

NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
[dict setObject:@"forKey:foo" forKey:foo];
[dict setObject:@"forKey:bar" forKey:bar];
[dict setObject:@"forKey:[NSValue... foo]" forKey:[NSValue valueWithPointer:foo]];
[dict setObject:@"forKey:[NSValue... bar]" forKey:[NSValue valueWithPointer:bar]];

NSLog(@"%@", [dict objectForKey:foo]); 
NSLog(@"%@", [dict objectForKey:bar]); 
NSLog(@"%@", [dict objectForKey:[NSValue valueWithPointer:foo]]); 
NSLog(@"%@", [dict objectForKey:[NSValue valueWithPointer:bar]]); 

Gives

2013-01-24 04:42:14.051 a.out[67640:707] forKey:foo
2013-01-24 04:42:14.052 a.out[67640:707] forKey:bar
2013-01-24 04:42:14.053 a.out[67640:707] forKey:[NSValue... foo]
2013-01-24 04:42:14.053 a.out[67640:707] forKey:[NSValue... bar]
like image 156
xenosoz Avatar answered Nov 01 '22 21:11

xenosoz


Your problem is that NSDictionary copies its keys. Either make your class implement NSCopying or use a CFMutableDictionary with a key callback that doesn't copy (it's toll-free bridged with NSMutableDictionary, so you can use it exactly the same after it's created).

like image 29
Chuck Avatar answered Nov 01 '22 20:11

Chuck


You may find it easier to use objc_setAssociatedObject/objc_getAssociatedObject. They're described here.

like image 25
Nicholas Riley Avatar answered Nov 01 '22 21:11

Nicholas Riley