Como eu uso objc_setAssociatedObject / objc_getAssociatedObject dentro de um object?

Se eu usar objc_setAssociatedObject / objc_getAssociatedObject dentro de uma implementação de categoria para armazenar uma variável de instância simulada em um método setter, como acessaria a chave no método getter já que qualquer variável declarada no método setter estaria fora do escopo do método getter?

Edit: Para esclarecer, se eu usar o seguinte padrão, onde devo declarar STRING_KEY para que eu possa usá-lo no método setter e no método 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 

Declare uma variável estática para que você possa usar seu endereço como chave. A chamada para objc_setAssociatedObject usa um void * e somente o endereço da sua variável estática é realmente usado, não o conteúdo de um NSString … que está apenas perdendo memory.

Você só precisa adicionar:

 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 

Eu sei que esta questão é antiga, mas eu acho que para completar existe outra maneira de usar objects associados que vale a pena mencionar. Essa solução utiliza @selector e, portanto, não há necessidade de nenhuma variável ou constante extra.

 @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 

(inspirado em http://www.tuaw.com/2013/04/10/devjuice-better-objective-c-associated-objects/ )

Para armazenamento associado void * keys, eu gosto desta maneira de fazer isso:

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

Isso evita ter outra string constante no executável, e definindo seu valor para o endereço de si mesmo, você obtém um bom comportamento de uniquing e const (assim, você obterá uma reclamação do compilador se fizer algo que altere o valor do key), sem quaisquer símbolos extras desnecessários exportados.

Declare uma variável estática (escopo de unidade de compilation) no nível superior do arquivo de origem. Isso pode ajudar a torná-lo significativo, algo assim:

 static NSString *MYSimulatedString = @"MYSimulatedString"; 

Muito perto. Aqui está um exemplo completo.

.h-file

 @interface NSObject (ExampleCategoryWithProperty) @property (nonatomic, retain) NSArray *laserUnicorns; @end 

.m-file

 #import  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 

Assim como uma propriedade normal – acessível com notação de ponto

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

Sintaxe mais fácil

Como alternativa, você poderia usar @selector(nameOfGetter) vez de criar um ponteiro estático. Por quê? Veja https://stackoverflow.com/a/16020927/202451 . Exemplo:

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

A resposta aceita já acertou, mas gostaria de acrescentar uma explicação: o ponto da “chave” é obter um identificador único (por processo / programa) que não terá colisões acidentais.

Imagine a chave sendo declarada como NSUInteger : muitas pessoas usariam valores padrão como 0 , 1 ou 42 . Especialmente se você estiver usando alguma biblioteca ou estrutura, é provável que ocorram colisões.

Então, em vez disso, algum engenheiro da Apple inteligente teve a idéia de declarar a chave para ser um ponteiro com a intenção de declarar uma variável e passar o ponteiro para essa variável como uma chave. O vinculador atribuirá a essa variável um endereço exclusivo em seu aplicativo e, portanto, você terá a garantia de obter um valor único e livre de colisão.

Na verdade, você pode passar qualquer valor que desejar, o ponteiro não é desreferenciado (testei isso). Então passando (void *)0 ou (void *)42 medida que a chave funciona, embora não seja uma boa idéia (então, por favor, não faça isso). Para objc_set/getAssociatedObject , tudo o que importa é que o valor passado como chave seja exclusivo dentro de seu processo / programa.