Я играл с распределением памяти (de) в простом приложении командной строки для 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 имеет два сильных указателя и, следовательно, счетчик сохранения 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;
}
Я ожидал, что слабый указатель станет висящим указателем, отправляющим сообщение, через которое может произойти сбой программы в третьем операторе 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).
Так что здесь происходит?