67 votes

Qu'est-ce que objc_setAssociatedObject() et dans quels cas faut-il l'utiliser ?

Dans un projet que j'ai pris en charge, l'auteur original a choisi d'utiliser objc_setAssociatedObject() et je ne sais pas exactement ce qu'il fait ni pourquoi ils ont décidé de l'utiliser.

J'ai décidé d'y jeter un coup d'œil et, malheureusement, la documentation n'est pas très descriptive quant à son objectif.

objc_setAssociatedObject
Définit une valeur associée pour un objet donné en utilisant une clé et une politique d'association données.
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
Paramètres
object
L'objet source de l'association.
key
La clé pour l'association.
value
La valeur à associer à la clé de l'objet. Passez nil pour effacer une association existante.
policy
La politique de l'association. Pour connaître les valeurs possibles, voir "Comportements des objets associatifs".

Alors, que fait exactement cette fonction et dans quels cas doit-elle être utilisée ?


Modifier après avoir lu les réponses

Quel est donc l'intérêt du code suivant ?

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);

Quel est l'intérêt d'associer le dispositif au contrôleur de vue s'il s'agit déjà d'une variable d'instance ?

59voto

Nikolai Ruhe Points 45433

objc_setAssociatedObject ajoute un magasin de clés et de valeurs à chaque objet Objective-C. Il permet de stocker des états supplémentaires pour l'objet, qui ne sont pas reflétés dans son instanciation. Elle vous permet de stocker un état supplémentaire pour l'objet, qui n'est pas reflété dans ses variables d'instance.

C'est très pratique lorsque vous voulez stocker des éléments appartenant à un objet en dehors de l'implémentation principale. L'un des principaux cas d'utilisation est dans les catégories où vous ne pouvez pas ajouter de variables d'instance. Dans ce cas, vous utilisez objc_setAssociatedObject pour attacher vos variables supplémentaires à la self objet.

Si vous utilisez la bonne politique d'association, vos objets seront libérés lorsque l'objet principal sera désaffecté.

34voto

7KV7 Points 19750

A partir des documents de référence sur Référence pour l'exécution d'Objective-C :

Vous utilisez le runtime Objective-C fonction objc_setAssociatedObject à faire une association entre un objet et un autre. La fonction prend quatre paramètres : l'objet source, une clé la valeur, et une politique d'association constante. La clé est un pointeur de type void.

  • La clé de chaque association doit être unique. Un modèle typique consiste à d'utiliser une variable statique.
  • La politique précise si l'objet associé est affecté,
    conservé ou copié, et si le
    l'association se fait de manière atomique ou
    de manière non anatomique. Ce modèle est
    similaire à celle des attributs de
    une propriété déclarée (voir "Propriété
    Attributs de déclaration"). Vous spécifiez la politique de la relation à l'aide une constante (voir
    objc_AssociationPolicy et
    Comportements associatifs d'objets).

Établir une association entre un tableau et une chaîne de caractères

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

Au point 1, l'aperçu de la chaîne est encore valide parce que la politique OBJC_ASSOCIATION_RETAIN spécifie que le tableau conserve l'objet l'objet associé. Lorsque le tableau est désalloué, cependant (au point 2), le tableau est libéré et donc dans ce également désalloué. Si vous essayez, par exemple, d'enregistrer la valeur de overview, vous générez une exception d'exécution d'exécution.

25voto

abbood Points 5959

Voici une liste de cas d'utilisation des associations d'objets :

un : Pour ajouter des variables d'instance aux catégories. En général, cette technique est conseillé contre, mais voici une exemple d'une utilisation légitime. Disons que vous voulez simuler des variables d'instance supplémentaires pour des objets que vous ne pouvez pas modifier (nous parlons de modifier l'objet lui-même, c'est-à-dire sans le sous-classer). Disons qu'il s'agit de définir un titre sur une 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

Aussi, aquí est un moyen assez complexe (mais génial) d'utiliser des objets associés à des catégories. Il permet essentiellement de passer un bloc à la place d'un sélecteur à une commande de type UIControl .


deux : Ajout dynamique d'informations d'état à un objet qui ne sont pas couvertes par ses variables d'instance en conjonction avec KVO.

L'idée est que votre objet acquiert des informations d'état uniquement pendant l'exécution (c'est-à-dire dynamiquement). L'idée est donc que, bien que vous puissiez stocker ces informations d'état dans une variable d'instance, le fait que vous attachiez ces informations à un objet instancié au moment de l'exécution et que vous l'associiez dynamiquement à l'autre objet, souligne le fait qu'il s'agit d'un état dynamique de l'objet.

Un excellent exemple qui illustre cela est este dans laquelle les objets associatifs sont utilisés avec KVO notifications. Voici un extrait du code (note : cette notification KVO n'est pas nécessaire pour faire fonctionner le code dans cette bibliothèque elle est plutôt mise là par l'auteur pour des raisons de commodité, en fait tout objet qui s'enregistre à cette notification sera notifié via KVO que des changements lui sont arrivés) :

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

prime : Jetez un coup d'œil à ceci discussion/explication d'objets associés par Mattt Thompson, auteur de la bibliothèque AFNetworking qui a fait date

6voto

verma Points 416

5voto

JeremyP Points 46808

Pour répondre à votre question révisée :

Quel est l'intérêt d'associer le dispositif au contrôleur de vue s'il s'agit déjà d'une variable d'instance ?

Il y a plusieurs raisons pour lesquelles vous pourriez vouloir faire cela.

  • la classe Device n'a pas de variable d'instance de contrôleur, ni de propriété et vous ne pouvez pas la modifier ou la sous-classer, par exemple si vous n'avez pas le code source.
  • vous voulez deux contrôleurs associés à l'objet périphérique et vous ne pouvez pas changer la classe du périphérique ou la sous-classer.

Personnellement, je pense qu'il est très rare d'avoir besoin d'utiliser des fonctions d'exécution Objective-C de bas niveau. Cela ressemble à une odeur de code pour moi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X