Avoid extra static variables for associated objects keys

前端 未结 3 450
刺人心
刺人心 2020-12-08 02:36

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

3条回答
  •  南方客
    南方客 (楼主)
    2020-12-08 03:37

    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.

提交回复
热议问题