objective framework developer apple iphone objective-c objective-c-runtime

iphone - framework - swift ios documentation



¿Qué es objc_setAssociatedObject() y en qué casos debería usarse? (4)

En un proyecto que he asumido, el autor original ha optado por usar objc_setAssociatedObject() y no estoy 100% claro de qué se trata o por qué decidieron usarlo.

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 clave dada y una política de asociación.
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
Parámetros
object
El objeto fuente para la asociación.
key
La clave para la asociación.
value
El valor para asociar con la tecla clave 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 de objetos asociativos".

Entonces, ¿qué hace exactamente esta función y en qué casos se debe utilizar?

Editar después de leer las respuestas

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?


Aquí hay una lista de casos de uso para asociaciones de objetos:

uno: para agregar variables de instancia a las categorías. En general, se desaconseja esta técnica, pero aquí hay un ejemplo de 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, he aquí una forma bastante compleja (pero asombrosa) de utilizar objetos asociados con categorías. Básicamente, le permite pasar un bloque en lugar de un selector a un UIControl .

dos: agregar dinámicamente información de estado a un objeto no cubierto por sus variables de instancia junto 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 ejemplo excelente que ilustra esto es esta biblioteca, en la que los objetos asociativos se usan con las notificaciones de 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 lo pone ahí para mayor comodidad, básicamente cualquier objeto que se registre a esto será notificado a través de KVO que los cambios le han sucedido):

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"]; }

bonus: echa un vistazo a esta discusión / explicación de objetos asociados por Matth Thompson, autor de la biblioteca AFNetworking seminal


De los documentos de referencia sobre Objective-C Runtime Reference :

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

  • La clave para cada asociación debe ser única. Un patrón típico es usar una variable estática.
  • La política especifica si el objeto asociado está asignado,
    retenido, o copiado, y si el
    asociación se hará atómicamente o
    no atómicamente Este patrón es
    similar a la de los atributos de
    una propiedad declarada (ver "Propiedad
    Atributos de declaración "). Usted especifica la política para la relación usando una constante (ver
    objc_AssociationPolicy y
    Comportamientos Asociativos de Objetos).

Establecer 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 vista general de cadenas sigue siendo válida porque la política OBJC_ASSOCIATION_RETAIN especifica que la matriz conserva el objeto asociado. Sin embargo, cuando la matriz está desasignada (en el punto 2), se libera la descripción general, por lo que en este caso también se desasigna. Si intenta, por ejemplo, registrar el valor de la vista general, generará una excepción en tiempo de ejecución.


Para responder a tu pregunta revisada:

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

Hay varias razones por las que puede querer hacer esto.

  • la clase de dispositivo no tiene una variable de instancia de controlador, o propiedad, y no puede cambiarla o subclase, por ejemplo, no tiene el código fuente.
  • quiere 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 usar funciones de tiempo de ejecución de Objective-C de bajo nivel. Esto parece un olor de código para mí.


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 desea 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í utiliza objc_setAssociatedObject para adjuntar sus variables adicionales al objeto self .

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