Wednesday, April 20, 2011

Weak-keyed dictionary in Objective-C

Hello,

I'm wondering if it's possible to have something similar to ActionScript 3's Dictionary object with weak keys in Objective-C. I want to be able to 'attach' an instance of a class to other arbitrary instances.

Example;

MetaData *meta = [MetaData metaDataForObject:someObject];
meta.whatever = foo;

And later:

foo = [MetaData metaDataForObject:someObject].whatever;
[foo doStuff];

The tricky part is that after the objected referenced by someObject is dealloc'd, I want the object referenced by meta to be released (and dealloc'd, assuming no client code has retained it).

Possible? I took a look at +[NSValue valueWithNonretainedObject:] but I'm not sure if this is what I want because there when I later query -[NSValue nonretainedObjectValue] it seems like I would get a pointer to garbage (how could NSValue zero the pointer when the object was dealloc'd?).

Thanks,

benjamin

From stackoverflow
  • Are you looking for NSHashMap perhaps? It does zeroing references.

    bvanderveen : I'm developing for iPhone and unfortunately NSHashMap doesn't seem to be available.
  • It sounds like what you're asking is the ability to react to a weak-referenced instance variable to be deallocated. You can certainly use the __weak attribute (with GC enabled) to create a weak reference, but there's no built-in mechanism to catch when such an attribute is zeroed after its target is GCed.

    If you really want this, your best bet is to use the same mechanism Apple's Key-Value Observing uses: method swizzling. Maintain a global table (such as a NSHashMap or NSMapTable) mapping objects to their corresponding metadata objects, then replace the dealloc/finalize methods in the class of the object you're attaching to with versions that look up the corresponding metadata object in the table and send a message to tear it down. (You also need another table or two that maps classes to their original dealloc/finalize methods.) JRSwizzle provides a nice interface to swizzling.

    If you want to to be really fancy, instead of overwriting the dealloc/finalize for all objects of the target class, you can create a proxy class and reassign the isa pointer for just that class, such that there's no performance hit on deallocation for the objects you're not watching. (KVO does this, too.)

    bvanderveen : Method swizzling sounds pretty straight-forward. Can you elaborate on the isa-swizzling technique you mentioned? As I understand it, that would allow me to effectively change the class of the object, thereby providing a new implementation of dealloc, correct?
    Nicholas Riley : Yes, that's correct.
    Nicholas Riley : Also note that in 10.5 there is a function you can use for this, which is preferable going forward: http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html#//apple_ref/c/func/object_setClass

0 comments:

Post a Comment