Я возился с выделением памяти в простом приложении командной строки для 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).
Так что же здесь происходит?