2011-05-06 11 views
60

En un proyecto que he tomado, el autor original ha optado por usar objc_setAssociatedObject() y no estoy 100% claro de qué se trata o por qué decidieron usarlo.¿Qué es objc_setAssociatedObject() y en qué casos debería usarse?

Decidí buscarlo y, desafortunadamente, los documentos no son muy descriptivos sobre su propósito.

objc_setAssociatedObject
establece un valor asociado para un objeto dado usando una política clave y de asociación dado.
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
Parámetros
object
El objeto de origen para la asociación.
key
La clave para la asociación.
value
El valor para asociar con la tecla para el objeto. Pase nil para borrar una asociación existente.
policy
La política para la asociación. Para conocer los valores posibles, consulte "Comportamientos asociativos de los objetos".

Entonces, ¿qué función cumple exactamente esta función y en qué casos debería utilizarse?


Edición después de la lectura responde

Entonces, ¿cuál es el punto en el siguiente código?

Device *device = [self.list objectAtIndex:[indexPath row]]; 
DeviceViewController *next = [[DeviceViewController alloc] initWithController:self.controller 
                      device:device 
                       item:self.rootVC.selectedItem]; 
    objc_setAssociatedObject(device, &kDeviceControllerKey, next, OBJC_ASSOCIATION_RETAIN); 

¿Cuál es el punto de asociar el dispositivo con el controlador de vista si ya es una variable de instancia?

Respuesta

30

A partir de los documentos de referencia en Objective-C Runtime Reference:

Se utiliza el tiempo de ejecución de Objective-C función objc_setAssociatedObject a hacer una asociación entre un objeto y otro . La función toma cuatro parámetros : el objeto de origen, una clave, el valor y una política de asociación constante. La clave es un puntero de vacío.

  • La clave para cada asociación debe ser única. Un patrón típico es utilizar una variable estática.
  • La política especifica si se asigna el objeto asociado,
    retenido, o copiado, y si la asociación
    se hacerse atómicamente o
    no atómicamente. Este patrón es
    similar al de los atributos de
    una propiedad declarada (ver "Propiedad
    Atributos de declaración").Especifique la política para la relación utilizando una constante (consulte
    objc_AssociationPolicy y
    Comportamientos asociativos de objeto).

establece una asociación entre una matriz y una cadena

static char overviewKey; 



NSArray *array = 

    [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil]; 

// For the purposes of illustration, use initWithFormat: to ensure 

// the string can be deallocated 

NSString *overview = 

    [[NSString alloc] initWithFormat:@"%@", @"First three numbers"]; 



objc_setAssociatedObject (

    array, 

    &overviewKey, 

    overview, 

    OBJC_ASSOCIATION_RETAIN 

); 



[overview release]; 

// (1) overview valid 

[array release]; 

// (2) overview invalid 

En el punto 1, la información general de cadena es siendo válida porque el OBJC_ASSOCIATION_RETAIN política especifica que la matriz conserva el objeto asociado. Cuando la matriz es desasignada, sin embargo (en el punto 2), se libera la descripción , por lo que en este caso también se desasignó. Si intenta, por ejemplo, , registrar el valor de descripción general, genera una excepción de tiempo de ejecución .

+0

Hola, estaba revisando la documentos con la intención de publicar una respuesta similar. Mientras me pegabas, me tomé la libertad de hacer un enlace de hipertexto en tu respuesta. Espero que no te importe. – JeremyP

+0

@JeremyP: Claro. Muchas gracias por eso. Perdido para agregar el enlace. Gracias por su contribución – visakh7

+0

Podría compartir algunas reputaciones si pudiera. : P – visakh7

52

objc_setAssociatedObject agrega un almacén de valores clave a cada objeto Objective-C. Le permite almacenar estados adicionales para el objeto, no reflejados en sus variables de instancia.

Es realmente conveniente cuando quiere almacenar cosas que pertenecen a un objeto fuera de la implementación principal. Uno de los casos de uso principales está en categorías donde no puede agregar variables de instancia. Aquí usa objc_setAssociatedObject para adjuntar sus variables adicionales al objeto self.

Al utilizar la política de asociación correcta, sus objetos se liberarán cuando se desasigna el objeto principal.

+0

Gracias por la explicación. Dudo si el código está usando la función de manera útil, después de leer esto. Edité la pregunta para incluir el código. – Jasarien

+0

¿No podemos usar un diccionario en este caso, mantener el objeto? – santhosh

+0

@ user3127620 Eso es (semánticamente) lo que hace 'objc_setAssociatedObject'. La ventaja de este mecanismo es que puede hacerlo sin alterar la clase (es decir, sin agregar un ivar). Entonces puede hacerlo en clases marco u otros casos donde no posee el código fuente. –

5

Para responder a su pregunta revisada:

¿Cuál es el punto en asociar el dispositivo con el controlador de vista si es ya una variable de instancia?

Existen varias razones por las que es posible que desee hacer esto.

  • La clase de dispositivo no tiene una variable de instancia de controlador ni propiedad y no puede cambiarla o subclase, p. Ej. usted no tiene el código fuente
  • desea dos controladores asociados con el objeto del dispositivo y no puede cambiar la clase del dispositivo o la subclase.

Personalmente, creo que es muy raro que necesite utilizar funciones de tiempo de ejecución de Objective-C de bajo nivel. Esto parece un olor de código para mí.

+0

Esta vez me golpeó: P. – visakh7

+2

Creo que estoy de acuerdo contigo. Huele Tengo toda la intención de hacer esto correctamente.Gracias por la aclaración. – Jasarien

24

Aquí es una lista de casos de uso para las asociaciones de objetos:

uno: Para añadir variables de instancia a las categorías. En general, esta técnica es advised en contra, pero aquí hay un example de un uso legítimo. Supongamos que quiere simular variables de instancia adicionales para objetos que no puede modificar (estamos hablando de modificar el objeto en sí mismo, es decir, sin subclases). Digamos establecer un título en un UIImage.

// UIImage-Title.h: 
@interface UIImage(Title) 
@property(nonatomic, copy) NSString *title; 
@end 

// UIImage-Title.m: 
#import <Foundation/Foundation.h> 
#import <objc/runtime.h> 

static char titleKey; 

@implementation UIImage(Title) 
- (NSString *)title 
{ 
    return objc_getAssociatedObject(self, &titleKey); 
} 

- (void)setTitle:(NSString *)title 
{ 
    objc_setAssociatedObject(self, &titleKey, title, OBJC_ASSOCIATION_COPY); 
} 
@end 

Además, here es una forma bastante compleja (pero impresionante) de la utilización de objetos asociados con las categorías .. que básicamente le permite pasar de un bloque en lugar de un selector a un UIControl.


dos: añadiendo dinámicamente información de estado a un objeto no cubierta por sus variables de instancia en conjunción con KVO.

La idea es que su objeto gane información de estado solo durante el tiempo de ejecución (es decir, dinámicamente). Entonces, la idea es que aunque puede almacenar esta información de estado en una variable de instancia, el hecho de que esté adjuntando esta información en un objeto instanciado en tiempo de ejecución y asociándolo dinámicamente con el otro objeto, está resaltando el hecho de que esto es un estado dinámico del objeto.

Un excelente ejemplo que ilustra esto es la biblioteca this, en la que los objetos asociativos se utilizan con las notificaciones KVO. Aquí hay un fragmento del código (nota: esta notificación de KVO no es necesaria para ejecutar hacer que el código en esa biblioteca funcione ... sino que el autor la pone allí para mayor comodidad, básicamente cualquier objeto que se registre a esto será notificado a través de KVO que los cambios han sucedido a él):

static char BOOLRevealing; 

- (BOOL)isRevealing 
{ 
    return [(NSNumber*)objc_getAssociatedObject(self, &BOOLRevealing) boolValue]; 
} 

- (void)_setRevealing:(BOOL)revealing 
{ 
    [self willChangeValueForKey:@"isRevealing"]; 
    objc_setAssociatedObject(self, &BOOLRevealing, 
     [NSNumber numberWithBool:revealing], OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
    [self didChangeValueForKey:@"isRevealing"]; 
} 

bonificación: echar un vistazo a este discussion/explanation de objetos asociados por mattt Thompson, autor de la biblioteca AFNetworking seminal

+0

¡Perfecto! ¡Exactamente lo que necesitaba! –

+0

Las razones uno y dos en su respuesta son las mismas. Ambos agregan una variable de instancia a un objeto a través de una categoría. – Jasarien

+0

@Jasarien mi mal ... los fusionó. – abbood

Cuestiones relacionadas