2013-05-15 4 views
13

Я знаю, что OBJC_ASSOCIATION_ASSIGN существует, но делает ли он нулевую ссылку, если целевой объект освобожден? Или это похоже на старые времена, когда эта ссылка должна быть обновлена, или мы рискуем плохой доступ позже?Использование objc_setAssociatedObject со слабыми ссылками

+0

Да, правда. Я попробую. – ultramiraculous

ответ

1

После проверки, ответ НЕТ.

Я побежал следующий код под IOS 6 Simulator, но это, вероятно, имеют такое же поведение с предыдущей итерации выполнения:

NSObject *test1 = [NSObject new]; 

NSObject __weak *test2 = test1; 

objc_setAssociatedObject(self, "test", test1, OBJC_ASSOCIATION_ASSIGN); 

test1 = nil; 

id test3 = objc_getAssociatedObject(self, "test"); 

В конце концов, test1 и test2 равны нулю, и test3 является указатель, ранее сохраненный в test1. Использование test3 приведет к попытке получить доступ к объекту, который уже был освобожден.

+0

Типо там? как «test1» относится к «тесту» и «тест2»? – Jeff

0

Это поведение не указано в документах или заголовках, насколько я могу судить, поэтому, скорее всего, это будет деталь реализации, на которую вы не должны рассчитывать, даже если бы вы смогли определить, что такое текущее поведение. Я бы предположил, что это не обнулено. Вот почему:

В общем, нет необходимости в nil ссылки в iVars во время -dealloc. Если объект отменен, не имеет значения, были ли его iVars обнулены, поскольку любой последующий доступ к освобожденному объекту или его iVars сам по себе является ошибкой программирования. На самом деле, я слышал, что некоторые утверждают, что лучше не удалить ссылки во время -dealloc, так как он сделает ошибочный доступ еще очевидным/разоблачить ошибки раньше.

EDIT: О, я думаю, я неправильно понял ваш вопрос. Вы хотите «обнулить слабые ссылки». Соответствующее хранилище, похоже, не поддерживает их. Вы можете сделать тривиальный проходной класс с одним ivar/свойством, обозначенным как __weak, и добиться такого же эффекта. Немного клодэй, но это сработает.

+0

Я имею в виду, в случае, если я смотрю, это не ошибка, если я попытаюсь получить доступ к объекту после его освобождения. Если у меня есть слабая ссылка, как ссылка на делегата, я ожидаю, что она может не существовать к моменту моего сообщения. – ultramiraculous

26

Как показано на ультракрасном уровне, OBJC_ASSOCIATION_ASSIGN не делает обнуление слабых ссылок, и вы рискуете получить доступ к освобожденному объекту. Но реализовать его очень легко. Вам просто нужно простой класс, чтобы обернуть объект со слабой ссылкой:

@interface WeakObjectContainer : NSObject 
@property (nonatomic, readonly, weak) id object; 
@end 

@implementation WeakObjectContainer 
- (instancetype) initWithObject:(id)object 
{ 
    if (!(self = [super init])) 
     return nil; 

    _object = object; 

    return self; 
} 
@end 

Тогда вы должны ассоциировать WeakObjectContainer как OBJC_ASSOCIATION_RETAIN (_NONATOMIC):

objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainer alloc] initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC); 

и использовать object свойство для доступа к нему в для того чтобы получить обнуления слабой ссылки:

id object = [objc_getAssociatedObject(self, &MyKey) object]; 
+1

Хе-хе! Действительно разумный подход. Любить это! Я буду помнить об этом. – MonsieurDart

+0

Почему бы просто не использовать NSValue :: valueWithNonretainedObject:? – AlexDenisov

+2

Поскольку '- [NSValue nonretainedObjectValue]' не возвращает * слабый * объект и, следовательно, не делает обнуление слабым ссылкой. – 0xced

4

еще один вариант похож на WeakObjectContainer:

- (id)weakObject { 
    id (^block)() = objc_getAssociatedObject(self, @selector(weakObject)); 
    return (block ? block() : nil); 
} 

- (void)setWeakObject:(id)object { 
    id __weak weakObject = object; 
    id (^block)() = ^{ return weakObject; }; 
    objc_setAssociatedObject(self, @selector(weakObject), 
          block, OBJC_ASSOCIATION_COPY); 
} 
Смежные вопросы