When using associated objects, an Objective-C runtime feature available starting from iOS 4 and OSX 10.6, it\'s necessary to define a key for storing and retrieving the obje
A slight variation on the idea @Gabriele Petronella discussed is to associate a dictionary to every object:
//NSObject+ADDLAssociatedDictionary.h
#import
@interface NSObject (ADDLAssociatedDictionary)
- (void)addl_setAssociatedObject:(id)object forKey:(id)key;
- (id)addl_associatedObjectForKey:(id)key;
@end
//NSObject+ADDLAssociatedDictionary.m
#import
@interface NSObject (ADDLAssociatedDictionaryInternal)
- (NSMutableDictionary *)addl_associatedDictionary;
@end
@implementation NSObject (ADDLAssociatedDictionary)
- (void)addl_setAssociatedObject:(id)object forKey:(id)key
{
if (object) {
self.addl_associatedDictionary[key] = object;
} else {
[self.addl_associatedDictionary removeObjectForKey:key];
}
}
- (id)addl_associatedObjectForKey:(id)key
{
return self.addl_associatedDictionary[key];
}
@end
@implementation NSObject (ADDLAssociatedDictionaryInternal)
const char addl_associatedDictionaryAssociatedObjectKey;
- (NSMutableDictionary *)addl_associatedDictionaryPrimitive
{
return objc_getAssociatedObject(self, &addl_associatedDictionaryAssociatedObjectKey);
}
- (void)addl_setAssociatedDictionaryPrimitive:(NSMutableDictionary *)associatedDictionary
{
objc_setAssociatedObject(self, &addl_associatedDictionaryAssociatedObjectKey, associatedDictionary, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSMutableDictionary *)addl_generateAssociatedDictionary
{
NSMutableDictionary *associatedDictionary = [[NSMutableDictionary alloc] init];
[self addl_setAssociatedDictionaryPrimitive:associatedDictionary];
return associatedDictionary;
}
- (NSMutableDictionary *)addl_associatedDictionary
{
NSMutableDictionary *res = nil;
@synchronized(self) {
if (!(res = [self addl_associatedDictionaryPrimitive])) {
res = [self addl_generateAssociatedDictionary];
}
}
return res;
}
@end
Then in our category on some subclass Derived of NSObject
//Derived+Additions.h
#import "Derived.h"
@interface Derived (Additions)
@property (nonatomic) id anAssociatedObject;
@end
//Derived+Additions.m
#import "NSObject+ADDLAssociatedDictionary.h"
@implementation Derived (Additions)
- (void)setAnAssociatedObject:(id)anAssociatedObject
{
[self addl_setAssociatedObject:anAssociatedObject forKey:NSStringFromSelector(@selector(anAssociatedObject))];
}
- (id)anAssociatedObject
{
return [self addl_associatedObjectForKey:NSStringFromSelector(@selector(anAssociatedObject))];
}
@end
One benefit of the associated dictionary approach in general is the added flexibility that comes from being able to set objects for keys that are generated at runtime, not to mention the much nicer syntax.
A benefit particular to using
NSStringFromSelector(@selector(anAssociatedObject))
is that NSStringFromSelector is guaranteed to give an NSString
representation of the selector which will always be an acceptable dictionary key. As a result, we don't have to worry at all (though I don't think it's a reasonable concern) about ABI changes.