Inconsistent object deallocation with ARC?

Я возился с выделением памяти в простом приложении командной строки для Mac OSX 10.7, созданном с помощью Xcode версии 4.2.1 с включенным ARC и настройками сборки по умолчанию. Я не могу объяснить поведение, которое я получаю, исходя из того, что я понимаю об ARC, поэтому я надеюсь, что кто-нибудь сможет объяснить, что здесь происходит.

Во-первых, в следующем коде я получаю ожидаемое поведение (обратите внимание, что вывод NLog() приведен в комментарии после соответствующего оператора)

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    NSObject *objPtr1 = [[NSObject alloc] init];
    NSObject *objPtr2 = objPtr1; 
    __weak NSObject *weakRef = objPtr1;
    NSLog(@"%@", [objPtr1 description]); // <NSObject: 0x1001107d0>
    objPtr1 = nil;
    NSLog(@"%@", [objPtr2 description]); // <NSObject: 0x1001107d0>
    objPtr2 = nil;
    NSLog(@"%@", [weakRef description]); // (null)
    return 0;
}

Итак, в приведенном выше коде, сразу после присвоения weakRef, экземпляр NSObject имеет два сильных указателя на него, и поэтому счетчик retain count равен 2. После обнуления objPtr1 остается один сохраняющийся указатель на экземпляр, поэтому он все еще в памяти и отвечает на сообщение description. После обнуления objPtr2 сильных указателей на объект не остается, и он деаллоцируется (я предполагаю, что это так, поскольку weakRef был обнулен). Пока все хорошо.

Теперь тот же код с небольшими изменениями:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    NSObject *objPtr1 = [[NSObject alloc] init];
    NSObject *objPtr2 = objPtr1; 
    __unsafe_unretained NSObject *weakRef = objPtr1; // __unsafe_unretained instead of just __weak
    NSLog(@"%@", [objPtr1 description]); // <NSObject: 0x1001107d0>

    objPtr1 = nil;
    NSLog(@"%@", [objPtr2 description]); // <NSObject: 0x1001107d0>

    objPtr2 = nil;
    NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>
    //why was the object instance not deallocated and the preceding statement not crash the program?
    return 0;
}

Я ожидал, что weakRef станет висячим указателем, посылающим сообщение, которое приведет к аварийному завершению программы в третьем операторе NSLog(), но, похоже, экземпляр объекта все еще жив и здоров.

Еще одна странность:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{

    NSObject *objPtr1 = [[NSObject alloc] init];
    NSObject *objPtr2 = objPtr1; 
    __weak NSObject *weakRef = objPtr1; // __weak again
    NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>

    objPtr1 = nil;
    NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>

    objPtr2 = nil;
    NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>

    return 0;

}

Последний код похож на первый (с использованием обнуленного указателя __weak); разница лишь в том, что сообщение описания было отправлено объекту через weakRef в каждом из трех вызовов NSLog(). Но в этот раз объект не деаллоцируется даже после удаления двух сильных ссылок (поскольку он все еще отвечает на сообщения через weakRef).

Так что же здесь происходит?

8
задан jrturton 7 February 2012 в 11:59
поделиться