65 votes

Comment utiliser objc_setAssociatedObject/objc_getAssociatedObject à l'intérieur d'un objet ?

Si j'utilise objc_setAssociatedObject/objc_getAssociatedObject dans une implémentation de catégorie pour stocker une variable d'instance simulée dans une méthode setter, comment puis-je accéder à la clé dans la méthode getter puisque toute variable déclarée dans la méthode setter est en dehors de la portée de la méthode getter ?

Edit : Pour clarifier, si je devais utiliser le modèle suivant, où devrais-je déclarer STRING_KEY afin de pouvoir l'utiliser à la fois dans la méthode setter et dans la méthode getter.

@interface NSView (simulateVar)
-(void)setSimualtedString:(NSString *)myString;
-(NSString *)simulatedString;
@end

@implementation NSView (simulateVar)

-(void)setSimualtedString: (NSString *)myString
{
    objc_setAssociatedObject(self, &STRING_KEY, myString, OBJC_ASSOCIATION_RETAIN);
}

-(NSString *)simulatedString
{
    return (NSString *)objc_getAssociatedObject(self, &STRING_KEY);
}

@end

62voto

Brent Priddy Points 546

Déclarez une variable statique afin de pouvoir utiliser son nom. adresse comme clé. L'appel à objc_setAssociatedObject prend un void* et seule l'adresse de votre variable statique est réellement utilisée, pas le contenu d'une NSString... ce qui ne fait que gaspiller de la mémoire.

Vous devez juste ajouter :

static char STRING_KEY; // global 0 initialization is fine here, no 
                        // need to change it since the value of the
                        // variable is not used, just the address

38voto

zlajo Points 1057

Je sais que cette question est assez ancienne, mais je pense que pour être complet, il y a une autre façon d'utiliser les objets associés qui mérite d'être mentionnée. Cette solution utilise @selector et il n'y a donc pas besoin d'une variable ou d'une constante supplémentaire.

@interface NSObject (CategoryWithProperty)

@property (nonatomic, strong) NSObject *property;

@end

@implementation NSObject (CategoryWithProperty)

- (NSObject *)property {
    return objc_getAssociatedObject(self, @selector(property));
}

- (void)setProperty:(NSObject *)value {
    objc_setAssociatedObject(self, @selector(property), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

(inspiré par http://www.tuaw.com/2013/04/10/devjuice-better-objective-c-associated-objects/ )

23voto

ipmcc Points 16609

Pour le stockage associé void * les clés, j'aime cette façon de faire :

static void * const kMyAssociatedStorageKey = (void*)&kMyAssociatedStorageKey; 

Cela évite d'avoir une autre chaîne constante dans l'exécutable, et en fixant sa valeur à l'adresse de lui-même, vous obtenez une bonne unicité, et const (vous recevrez donc une plainte du compilateur si vous faites quelque chose qui change la valeur de la clé), sans aucun symbole exporté inutile.

16voto

Nicholas Riley Points 26161

Déclarez une variable statique (de portée unitaire de compilation) au niveau supérieur du fichier source. Il peut être utile de lui donner un sens, quelque chose comme ceci :

static NSString *MYSimulatedString = @"MYSimulatedString";

9voto

hfossli Points 6815

Assez proche. Voici un exemple complet.

Fichier .h

@interface NSObject (ExampleCategoryWithProperty)

@property (nonatomic, retain) NSArray *laserUnicorns;

@end

.m-file

#import <objc/runtime.h>

static void * LaserUnicornsPropertyKey = &LaserUnicornsPropertyKey;

@implementation NSObject (ExampleCategoryWithProperty)

- (NSArray *)laserUnicorns {
    return objc_getAssociatedObject(self, LaserUnicornsPropertyKey);
}

- (void)setLaserUnicorns:(NSArray *)unicorns {
    objc_setAssociatedObject(self, LaserUnicornsPropertyKey, unicorns, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
}

@end

Tout comme une propriété normale - accessible avec la notation par points

NSObject *myObject = [NSObject new];
myObject.laserUnicorns = @[@"dipwit", @"dipshit"];
NSLog(@"Laser unicorns: %@", myObject.laserUnicorns);

Une syntaxe plus facile

Vous pouvez également utiliser @selector(nameOfGetter) au lieu de créer un pointeur statique. Pourquoi ? Voir https://stackoverflow.com/a/16020927/202451 . Exemple :

- (NSArray *)laserUnicorns {
    return objc_getAssociatedObject(self, @selector(laserUnicorns));
}

- (void)setLaserUnicorns:(NSArray *)unicorns {
    objc_setAssociatedObject(self, @selector(laserUnicorns), unicorns, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
}

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