Попробуйте использовать пользовательский класс вместо NSData
для d
, например MyData
. Реализуйте в нем dealloc
метод и установите в нем точку останова. Вы увидите, что dealloc
вызывается пулом авто-выпуска после последнего NSAssert
. Только после этой недели ссылка станет nil
.
ADD:
Похоже, я должен расширить свой ответ, чтобы понять, почему это так работает.
Сначала давайте рассмотрим ваш пример (из комментариев):
NSData* data = [[NSData alloc] init];
__weak NSData* weakRef = data;
data = nil;
NSAssert(weakRef == nil, @"Failed to zero");
Работает как положено, weakRef
становится nil
после data = nil
. Следующий пример тоже работает:
NSData* data = [[NSData alloc] init];
__weak NSData* weakRef = data;
NSLog(@"%@", data);
data = nil;
NSAssert(weakRef == nil, @"Failed to zero");
Но последний пример не работает:
NSData* data = [[NSData alloc] init];
__weak NSData* weakRef = data;
NSLog(@"%@", weakRef);
data = nil;
NSAssert(weakRef == nil, @"Failed to zero");
Единственное отличие состоит в том, что мы используем слабую ссылку на выходной журнал. Почему?
(остальная часть ответа может быть неправильной :))
Представьте, что вы NSLog
(или любая другая функция / селектор, которую мы вызывали до data = nil
), полагаются на то, что аргумент не равен nil
. Например, он имеет «if (arg == nil) return;» в самом начале.
В многопоточной среде слабая ссылка может стать nil
после if
.
Так что правильно написанная функция должна выглядеть так:
// ...
T* local_arg = arg; // NOTE: it is strong!
if (local_arg == nil)
return;
// work with local_arg here, not with arg
// ...
Но обычно мы не хотим делать это везде - это будет ужасно. Поэтому мы хотим быть уверены, что аргументы не исчезнут где-то посередине. Компилятор делает это за нас, автоматически выпуская слабую ссылку.
Итак, должно быть понятно, почему ваш GMWeakRefObj
контрольный пример не работает - weakRef
автоматически высвобождается перед вызовом setObject
setter.