Объекты, связанные с Objective-C, просачиваются в ARC

Я столкнулся со странным поведением objc_setAssociatedObject под ARC. Рассмотрим следующий код:

static char ASSOC_KEY;

@interface DeallocTester : NSObject
@end

@implementation DeallocTester
- (void) dealloc
{
    NSLog(@"DeallocTester deallocated");
    //objc_setAssociatedObject(self, &ASSOC_KEY, nil, OBJC_ASSOCIATION_RETAIN);
}
@end

@implementation AppDelegate
- (void) applicationDidFinishLaunching:(UIApplication *)application
{
    NSObject *test = [[DeallocTester alloc] init];
    objc_setAssociatedObject(test, &ASSOC_KEY, [[DeallocTester alloc] init],
                             OBJC_ASSOCIATION_RETAIN);
}

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

Я ожидаю, что будет вызван -dealloc первого объекта, а затем связанный с ним объект также будет освобожден, но я вижу, что сообщение "DeallocTester deallocated" печатается только один раз. Если я раскомментирую строку objc_setAssociatedObject в -dealloc, второй объект тоже будет освобожден.

В ссылке на Objective-C указано, что связанные объекты автоматически освобождаются при уничтожении объекта. Это компилятор/ARC/какая-то проблема или я что-то упустил?

Обновить

Этот пример кода действительно работает, если вы запускаете его из совершенно нового проекта. Но у меня есть два проекта с поддержкой ARC, в которых ее нет. Я проведу небольшое расследование и предоставлю лучший образец.

Обновление 2

Я заполнил rdar://10636309, связанная утечка объектов, если объекты NSZombie включены в проекте с поддержкой ARC.


person iHunter    schedule 03.01.2012    source источник
comment
Если вы используете LLVM3+, почему вы используете связанные объекты? Вместо этого вы можете просто создавать iVars и свойства в категориях класса.   -  person Abizern    schedule 03.01.2012
comment
@Abizern Я собираюсь добавить ивары в NSObject, ивары AFAIR можно добавлять только в категорию расширения класса, а не в произвольную.   -  person iHunter    schedule 03.01.2012
comment
@Абизерн Правда? Как создать ивар в категории?   -  person jlehr    schedule 03.01.2012
comment
@Abizern @interface NSObject (MyCat) { int myivar; } @end -› Иваров нельзя размещать в категориях   -  person iHunter    schedule 03.01.2012


Ответы (2)


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

Насколько я понимаю, когда зомби-объекты включены, обычные экземпляры заменяются на NSZombie при освобождении, но все связанные объекты остаются в живых! Остерегайтесь такого поведения!

Я создал rdar://10636309

Обновление: существует обходной путь от Седрика Лути, и эта проблема, похоже, исправлена. в iOS 6.

person iHunter    schedule 03.01.2012
comment
Хех, еще одна веская причина не оставлять NSZombie включенным по умолчанию. - person jlehr; 03.01.2012
comment
@jlehr А каковы другие причины? Я всегда включаю их в своих проектах и ​​пока не вижу никаких недостатков. Я что-то упускаю? Спасибо. - person iHunter; 03.01.2012
comment
Если оставить зомби включенным, это может скрыть множество проблем и, конечно же, приведет к утечке памяти из вашего приложения. - person jlehr; 03.01.2012
comment
@jlehr Ты уверен? Без зомби вы не сможете надежно найти ошибки с доступом к освобожденному объекту, пока он не будет стерт другим объектом и не произойдет сбой. Но вам может не повезти не сбой, а вызов абсолютно не относящегося к делу объекта, так что жить без зомби имхо действительно опаснее). Да, с памятью могут быть проблемы, но я пока не видел реальных проблем, видимо они используют какую-то экономию памяти или мне просто повезло :) - person iHunter; 03.01.2012
comment
Нет причин оставлять зомби включенными, если только вы не занимаетесь активным устранением проблем с управлением памятью. - person jlehr; 03.01.2012
comment
Я заметил это при запуске инструмента Leaks. Кажется, я припоминаю, что переопределенное Dealloc даже не вызывалось для самого объекта, но свойства ARC обнулялись, как если бы было вызвано Dealloc. Страшный. Кстати, +1 за включение зомби во время цикла разработки/отладки. - person Steven Kramer; 12.01.2012
comment
@iHunter В определенных обстоятельствах NSZombies может молча разрешить запуск кода сбоя. - person Nate Chandler; 16.08.2012

Код, который вы разместили, работает точно так, как рекламируется в ARC. Я переписал вашу реализацию dealloc, чтобы сделать ее немного более очевидной.

- (void)dealloc
{
    NSLog(@"deallocating %@", self);
}

Вот полученный журнал:

2012-01-03 06:49:39.754 ARC  Stuff[47819:10103] deallocating <DeallocTester: 0x6878800>
2012-01-03 06:49:39.756 ARC  Stuff[47819:10103] deallocating <DeallocTester: 0x688b630>

Вы уверены, что компилируете с включенным ARC?

person jlehr    schedule 03.01.2012
comment
Вау! Какую версию ОС/XCode вы используете? - person iHunter; 03.01.2012
comment
Я тоже. Теперь я снова проверю в новом проекте. - person iHunter; 03.01.2012
comment
Я проверил свой код на свежем проекте, он работает! Но у меня есть два больших проекта с поддержкой ARC, в которых происходит утечка одного и того же кода! Магия. Похоже, я должен предоставить лучший пример кода. - person iHunter; 03.01.2012
comment
Проверьте флаги компилятора для конкретных файлов и убедитесь, что вы не используете -f-no-obj-arc для файла .m, в который вы это поместили, возможно? - person Ash Furrow; 03.01.2012