Re: Sensible way to extend base class?
Re: Sensible way to extend base class?
- Subject: Re: Sensible way to extend base class?
- From: Louis Gerbarg <email@hidden>
- Date: Thu, 21 May 2009 07:09:10 -0400
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 (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