As several people have mentioned, doing this kind of thing is very skanky,
and it won't work properly under GC without some additional machinery. But
if GC is not a concern you can do something that works with a bit grotesque
monkey patching.
The below code is generic, but it mucks with everything. I recommend you
always trim it down from NSObject to whatever class you are actually doing
it to.

Louis

#import <pthread.h>

#import <Foundation/Foundation.h>


@interface NSObject (LGAssociativeStorage)

@property (retain) id associatedObject;

@end

-----------------------------------------------------------


#import <objc/runtime.h>

#import "LGAssociativeStorage.h"


/* We are using STL containers because:

   1) Using Objective C containers can cause deallocs which cause recursion
issues

   2) STL containers are high perf containers that don't introduce external
code dependencies

   Ideally one could include a thread safe map implementation, but I don't
need one currently

*/


#include <map>


typedef std::map<id, __strong id> idMap_t;

typedef std::pair<id, __strong id> idPair_t;


static NSMutableDictionary * data = nil;

static pthread_mutex_t data_lock = PTHREAD_MUTEX_INITIALIZER;

static IMP gOriginalNSObjectDealloc = nil;

static idMap_t associatedObjectMap;


static

void removeAssociatedObjectFromMap(id self) {

  idMap_t::iterator iter = associatedObjectMap.find(self);

if( iter != associatedObjectMap.end() ) {

[iter->second release];

associatedObjectMap.erase(iter);

}

}


static

id newNSObjectDealloc(id self, SEL deallocSelector, ...) {

pthread_mutex_lock(&data_lock);

removeAssociatedObjectFromMap(self);

pthread_mutex_unlock(&data_lock);

return gOriginalNSObjectDealloc(self, deallocSelector);

}


static void initIfNecessary(void) {

if (!data) {

data = [[NSMutableDictionary alloc] init];

 // The below line of code is abusive... in the future the Objective C
runtime will use it as evidence

// that I am an unfit software engineer and take custody of all my code

gOriginalNSObjectDealloc = class_replaceMethod([NSObject class], @selector(
dealloc), newNSObjectDealloc, "v@:");

}

}




@implementation NSObject (LGAssociativeStorage)


- (id) associatedObject {

id retval = nil;

pthread_mutex_lock(&data_lock);

initIfNecessary();

idMap_t::iterator iter = associatedObjectMap.find(self);

if( iter != associatedObjectMap.end() ) {

retval = iter->second;

}

pthread_mutex_unlock(&data_lock);

return retval;

}


- (void) setAssociatedObject:(id)object_ {

pthread_mutex_lock(&data_lock);

initIfNecessary();

removeAssociatedObjectFromMap(self);

[object_ retain];

associatedObjectMap.insert(idPair_t(self, object_));

pthread_mutex_unlock(&data_lock);

}


@end
_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to