Подтвердить что ты не робот

Как использовать объект objc_setAssociatedObject/objc_getAssociatedObject внутри объекта?

Если я использую objc_setAssociatedObject/objc_getAssociatedObject внутри реализации категории для хранения имитируемой переменной экземпляра в методе setter, как бы получить доступ к ключу в методе getter, так как любые переменные, объявленные в методе setter, будут выходить за пределы объекта getter метод?

Изменить: Чтобы уточнить, должен ли я использовать следующий шаблон, где я должен объявить STRING_KEY, чтобы использовать его как в методе установки, так и в методе 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
4b9b3361

Ответ 1

Объявите статическую переменную, чтобы вы могли использовать ее адрес в качестве ключа. Вызов objc_setAssociatedObject принимает пустоту *, и на самом деле используется только адрес вашей статической переменной, а не содержимое NSString..., которое только растрачивает память.

Вам просто нужно добавить:

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

Ответ 2

Я знаю, что этот вопрос ушел, но я думаю, что для полноты есть другой способ использования связанных объектов, которые стоит упомянуть. Это решение использует @selector, и поэтому нет необходимости в каких-либо дополнительных переменных или константах.

@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

(вдохновленный http://www.tuaw.com/2013/04/10/devjuice-better-objective-c-associated-objects/)

Ответ 3

Для связанных ключей хранения void * мне нравится этот способ:

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

Это позволяет избежать использования другой постоянной строки в исполняемом файле, и, установив ее значение в адрес самого себя, вы получите хороший uniquing и const поведение (так что вы номинально получите жалобу компилятора, если вы сделаете что-то, что измените значение ключа), без лишних лишних экспортированных символов.

Ответ 4

Объявить статическую (компиляционную единицу-область) переменную на верхнем уровне исходного файла. Это может помочь сделать его значимым, что-то вроде этого:

static NSString *MYSimulatedString = @"MYSimulatedString";

Ответ 5

Совсем близко. Вот полный пример.

.h файл

@interface NSObject (ExampleCategoryWithProperty)

@property (nonatomic, retain) NSArray *laserUnicorns;

@end

ой файл

#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

Точно так же, как нормальное свойство - доступно с точечной нотой

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

Простой синтаксис

В качестве альтернативы вы можете использовать @selector(nameOfGetter) вместо создания статического указателя. Зачем? См. fooobar.com/questions/81102/.... Пример:

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

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

Ответ 6

Принятый ответ уже получил это правильно, но я хотел бы добавить объяснение: точкой "ключа" является получение уникального (для каждого процесса) идентификатора, который не будет иметь случайных столкновений.

Представьте, что ключ объявлен как NSUInteger: многие люди будут использовать стандартные значения, такие как 0, 1 или 42. Особенно, если вы используете какую-либо библиотеку или фреймворк, вероятны столкновения.

Итак, у какого-то умного инженера Apple возникла идея объявить ключ указателем с намерением объявить переменную и передать указатель на эту переменную в качестве ключа. Компонент свяжет эту переменную с уникальным в своем приложении адресом, поэтому вам гарантировано получить уникальное значение без конфликтов.

Фактически, вы можете передать любое значение, которое вам нравится, указатель не разыменован (я его тестировал). Итак, передаем (void *)0 или (void *)42, поскольку ключ работает, хотя это не очень хорошая идея (так что, пожалуйста, не делайте этого). Для objc_set/getAssociatedObject все, что имеет значение, - это то, что значение, переданное как ключ, уникально в вашем процессе/программе.