Dans un projet que j'ai entrepris, l'auteur d'origine a choisi d'utiliser objc_setAssociatedObject()
et je ne sais pas à 100% ce qu'il fait ni pourquoi il a décidé de l'utiliser.
J'ai décidé de le rechercher et, malheureusement, les documents ne sont pas très descriptifs sur son objectif.
objc_setAssociatedObject
Définit une valeur associée pour un objet donné à l'aide d'une clé et d'une stratégie d'association données.void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
Paramètresobject
L'objet source de l'association.key
La clé de l'association.value
La valeur à associer à la touche clé de l'objet. Passez à zéro pour effacer une association existante.policy
La politique de l'association. Pour 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 le point dans le 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 périphérique au contrôleur de vue s'il s'agit déjà d'une variable d'instance?
A partir des documents de référence sur Objective-C Runtime Reference :
Vous utilisez la fonction d'exécution Objective-C
objc_setAssociatedObject
pour faire une association entre un objet et un autre. La fonction prend quatre paramètres: l'objet source, une clé, la valeur et une constante de stratégie d'association. La clé est un pointeur vide.
- La clé de chaque association doit être unique. Un modèle typique consiste à utiliser une variable statique.
- La politique spécifie si l'objet associé est affecté,
conservé ou copié, et si le
l'association doit être faite par voie atomique ou
non atomique. 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 stratégie de la relation à l'aide d'une constante (voir
objc_AssociationPolicy et
Comportements des objets associatifs).
Établir une association entre un tableau et une chaîne
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, la vue d'ensemble des chaînes est toujours valide car la stratégie OBJC_ASSOCIATION_RETAIN spécifie que le tableau conserve l'objet associé. Cependant, lorsque le tableau est désalloué (au point 2), la vue d'ensemble est libérée et, dans ce cas, également désallouée. Si vous essayez, par exemple, de consigner la valeur de la vue d'ensemble, vous générez une exception d'exécution.
objc_setAssociatedObject
ajoute un magasin de valeurs clés à chaque objet Objective-C. Il vous permet de stocker un état supplémentaire pour l'objet, non reflété dans ses variables d'instance.
C'est vraiment pratique lorsque vous souhaitez stocker des objets appartenant à un objet en dehors de l'implémentation principale. L'un des principaux cas d'utilisation se trouve dans des catégories où vous ne pouvez pas ajouter de variables d'instance. Ici, vous utilisez objc_setAssociatedObject
pour attacher vos variables supplémentaires à l'objet self
.
Lorsque vous utilisez la bonne stratégie d'association, vos objets seront libérés lorsque l'objet principal sera désalloué.
Voici une liste de cas d'utilisation pour les associations d'objets:
un: Pour ajouter des variables d'instance aux catégories. En général, cette technique est conseillée contre, mais voici un exemple d'une utilisation légitime. Supposons que vous souhaitiez 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 sous-classement). Disons que définir un titre sur 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
En outre, ici est une manière assez complexe (mais géniale) d'utiliser des objets associés avec des catégories .. il vous permet essentiellement de passer un bloc au lieu d'un sélecteur à un UIControl
.
deux: Ajout dynamique d'informations d'état à un objet non couvert par ses variables d'instance en conjonction avec KVO.
L'idée est que votre objet obtient 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 attachez ces informations à un objet instancié au moment de l'exécution et que vous les associez dynamiquement à l'autre objet, vous mettez en évidence le fait qu'il s'agit un état dynamique de l'objet.
Un excellent exemple qui illustre cela est la bibliothèque this , dans laquelle les objets associatifs sont utilisés avec les notifications KVO . Voici un extrait du code (note: cette notification KVO n'est pas nécessaire pour exécuter faire fonctionner le code dans cette bibliothèque .. plutôt il est mis là par l'auteur pour plus de commodité, fondamentalement tout objet qui s'enregistre 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"];
}
bonus: jetez un œil à cette discussion/explication des objets associés par Mattt Thompson, auteur de la bibliothèque séminale AFNetworking
Pour répondre à votre question révisée:
Quel est l'intérêt d'associer le périphérique 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.
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.