Свързани с 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 Ще добавя ivars към NSObject, AFAIR ivars може да се добавя само към категория за разширение на клас, а не към произволна.   -  person iHunter    schedule 03.01.2012
comment
@Abizern Наистина ли? Как се създава ivar в категория?   -  person jlehr    schedule 03.01.2012
comment
@Abizern @interface NSObject (MyCat) { int myivar; } @end -› Ivars не могат да бъдат поставяни в категории   -  person iHunter    schedule 03.01.2012


Отговори (2)


Открих източник на проблем - активирах NSZombie обекти и в двата си проекта, където се появява този бъг.

Доколкото разбирам, когато зомби обектите са активирани, нормалните екземпляри се заменят с NSZombie при освобождаване, но всички свързани обекти остават живи! Пазете се от това поведение!

Създадох rdar://10636309

Актуализация: Има заобиколно решение от Cédric Luthi и този проблем изглежда е решен в 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 Сигурен ли си? Без зомбита не можете надеждно да намерите грешки с достъп до освободен обект, докато той не бъде изтрит от друг обект и настъпи срив. Но може да имате нещастие да не се сринете, а да се обадите на абсолютно несвързан обект, така че наистина е по-опасно да живеете без зомбита IMO). Да, паметта може да е проблем, но все още не съм виждал реални проблеми, изглежда използват някакъв вид запазване на паметта или просто имам късмет :) - person iHunter; 03.01.2012
comment
Няма причина да оставяте зомбита активирани, освен ако не отстранявате активно проблеми с управлението на паметта. - person jlehr; 03.01.2012
comment
Забелязах това, когато стартирах инструмента за течове. Изглежда си спомням, че отменения 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
Еха! Каква версия на OS/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