variable usar sirve que para metodos metodo estaticos estatico estaticas ejemplo definicion cuando clase objective-c objective-c-runtime associated-object

objective-c - usar - variable static java



Evitar variables estáticas adicionales para las claves de objetos asociados. (3)

De acuerdo con esta entrada del blog de Erica Sadun (cuyos créditos van a Gwynne Raskind ), la hay.

objc_getAssociatedObject y objc_getAssociatedObject requieren una clave para almacenar el objeto. Dicha clave debe ser un puntero de void constante. Así que al final solo necesitamos una dirección fija que se mantenga constante en el tiempo.

Resulta que la implementación de @selector proporciona casi lo que necesitamos, ya que utiliza direcciones fijas.

Por lo tanto, podemos simplemente deshacernos de la declaración clave y simplemente usar la dirección de selección de nuestra propiedad.

Así que si estás asociando en tiempo de ejecución una propiedad como

@property (nonatomic, retain) id anAssociatedObject;

Podemos proporcionar implementaciones dinámicas para su getter / setter que se parecen a

- (void)setAnAssociatedObject:(id)newAssociatedObject { objc_setAssociatedObject(self, @selector(anAssociatedObject), newAssociatedObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (id)anAssociatedObject { return objc_getAssociatedObject(self, @selector(anAssociatedObject)); }

Muy limpio y definitivamente más limpio que definir una clave variable estática adicional para cada objeto asociado.

¿Es esto seguro?

Como esto depende de la implementación, una pregunta legítima es: ¿se romperá fácilmente? Citando la entrada del blog.

Apple probablemente tendría que implementar un ABI completamente nuevo para que eso suceda

Si tomamos esas palabras para ser verdad, entonces es razonablemente seguro.

Cuando se utilizan objetos asociados, una función de tiempo de ejecución de Objective-C disponible a partir de iOS 4 y OSX 10.6, es necesario definir una clave para almacenar y recuperar el objeto en tiempo de ejecución.

El uso típico es definir la clave como sigue

static char const * const ObjectTagKey = "ObjectTag";

y luego usar es almacenar el objeto

objc_setAssociatedObject(self, ObjectTagKey, newObjectTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

y recuperarlo

objc_getAssociatedObject(self, ObjectTagKey);

(ejemplo tomado por http://oleb.net/blog/2011/05/faking-ivars-in-objc-categories-with-associative-references/ )

¿Existe una forma más clara de definir la clave de objeto asociada, que no implique la declaración de variables adicionales?


Si necesita acceder a la clave desde fuera del alcance de un solo método, un buen patrón para esto que conduce a un código más legible es crear un puntero que simplemente apunte a su propia dirección en la pila. Por ejemplo:

static void const *MyAssocKey = &MyAssocKey;

Si solo necesita acceso dentro del alcance de un solo método, puede usar _cmd , que se garantiza que es único. Por ejemplo:

objc_setAssociatedObject(obj, _cmd, associatedObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);


Una pequeña variación en la idea que discutió @Gabriele Petronella es asociar un diccionario a cada objeto:

//NSObject+ADDLAssociatedDictionary.h #import <Foundation/Foundation.h> @interface NSObject (ADDLAssociatedDictionary) - (void)addl_setAssociatedObject:(id)object forKey:(id<NSCopying>)key; - (id)addl_associatedObjectForKey:(id<NSCopying>)key; @end //NSObject+ADDLAssociatedDictionary.m #import <objc/runtime.h> @interface NSObject (ADDLAssociatedDictionaryInternal) - (NSMutableDictionary *)addl_associatedDictionary; @end @implementation NSObject (ADDLAssociatedDictionary) - (void)addl_setAssociatedObject:(id)object forKey:(id<NSCopying>)key { if (object) { self.addl_associatedDictionary[key] = object; } else { [self.addl_associatedDictionary removeObjectForKey:key]; } } - (id)addl_associatedObjectForKey:(id<NSCopying>)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

Luego en nuestra categoría en alguna subclase Derivada de 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

Una ventaja del enfoque de diccionario asociado en general es la flexibilidad adicional que se obtiene al poder configurar objetos para las claves que se generan en tiempo de ejecución, sin mencionar la sintaxis mucho más agradable.

Un beneficio particular al uso

NSStringFromSelector(@selector(anAssociatedObject))

es que se garantiza que NSStringFromSelector dará una representación NSString del selector que siempre será una clave de diccionario aceptable. Como resultado, no tenemos que preocuparnos en absoluto (aunque no creo que sea una preocupación razonable) sobre los cambios de ABI.