Objective - C отсчет ссылок, когда указатель установлен в ноль (без дуги)
Я пытаюсь понять, как работает подсчет ссылок, поэтому отключил ARC и написал простой класс: (Foo.h не вставляется, так как он немодифицирован)
Фу.m
@implementation Foo
- (instancetype)init
{
NSLog(@"Init object");
return [super init];
}
- (void)dealloc
{
NSLog(@"Dealloc object");
[super dealloc];
}
@end
Главная.m
#import <Foundation/Foundation.h>
#import "Foo.h"
int main(int argc, const char * argv[]) {
Foo *obj = [[Foo alloc] init];
obj = nil;
return 0;
}
Теперь я ожидаю увидеть журнал dealloc object, потому что единственная ссылка на объект Foo исчезла, но единственное сообщение, которое я получаю, - это init object.
Почему я не вижу его? Разве объект не освобождается, когда я назначаю obj = nil?
2 ответа:
Нет. Если вы не используете ARC, объект освобождается при вызове
[obj release];. (ARC вставляет эти вызовы для вас.) Установкаobjвnilничего не делает с точки зрения управления памятью (хотя и создает объект, до которого вы больше не можете добраться!).В основном, в какао без дуги:
- вы вызываете
[obj retain], Если хотите стать владельцем объекта. (allocделает это для вас.)- вы вызываете
[obj release], когда хотите отказаться от права собственности на объект.releaseв свою очередь вызываетdeallocкогда счетчик удержания объекта достигает 0.- вы вызываете
[obj autorelease], когда хотите отказаться от владения объектом вне его текущей области действия. Чаще всего это происходит, когда вы возвращаете объект из метода (и не хотите сохранять право собственности на него).
Пара дополнительных наблюдений, чтобы расширить превосходный ответ мипади:
В коде без дуги установка переменной в
nilне будет освобождать объект. Вы должны явным образомrelease/autoreleaseэто.Чтобы быть более точным об этом, если право собственности было передано вам (то есть вы получаете объект от метода, имя которого начинается с любого
Суть в том, что просто установить переменную вalloc,new,copy, илиmutableCopy), то вы несете ответственность за явный вызовrelease/autorelease.nilнедостаточно.- Я не решаюсь упомянуть об этом, опасаясь затуманить проблему, но когда речь идет о свойствах, это немного отличается. При использовании свойств вызов задатчика свойства
retainавтоматически создаст объектretainдля вас. Если вы позже установите свойство вnil, то сеттер будет автоматическиreleaseего для вас.Представьте себе класс, подобный Итак:
@interface Bar : NSObject @property (nonatomic, retain) Foo *foo; @endЕсли вы хотите установить свойство foo, вы можете сделать следующее
Foo *f = [[Foo alloc] init]; // create Foo object with +1 retain count self.foo = f; // the `retain` property will increase retain count to +2 [f release]; // resolve the local strong reference, reducing retain count back to +1Или, проще говоря:
self.foo = [[[Foo alloc] init] autorelease];Что они делают, так это создают объект
Fooс числом удержания +1. Задавая свойствоfoo, вы создаете другую ссылкуstrongи, таким образом, получаете число удержания +2. А когда ты тогда ...release/autoreleaseэто, число удержания падает обратно до +1.Позже, когда вы закончите с
fooи захотите освободить его, вы просто вызовете снова сеттер, на этот раз со значениемnil:Это снимает сильную ссылку, которую свойствоself.foo = nil; // resolve the `retain` done by the property, reducing the retain count to +0fooсохраняет на объект. Вы не звонитеreleaseсебе (по крайней мере, в свойстве). Очевидно, что когда вы вызываете сеттер со значениемnil, предыдущий объект не только освобождается,но если это была последняя сильная ссылка, объект будет освобожден и для вас.Короче говоря, исходное
allocсмещено на arelease/autorelease, не от кого бы то ни было установка переменной вnil. Тем не менее, установка свойстваretainразрешена путем установки этого свойства вnil.
Пара заключительных замечаний.
Я бы предложил, чтобы при написании кода без дуги вы внимательно изучили руководство по программированиюAdvanced Memory Management, особенно главуMemory Management Policy .
Статический анализатор Xcode (сдвиг+команда+B , или "Analyze "в меню" Product " Xcode) отлично справляется с выявлением проблем с памятью, которые беспокоят код без дуги. Всегда убедитесь, что у вас нет абсолютно никаких предупреждений от статического анализатора.
При использовании инструментов инструмент распределения имеет функцию, называемую "учет отсчетов ссылок" (см. https://stackoverflow.com/a/14105056/1271826 ). если вы обнаруживаете, что какой-то объект не освобождается, этот инструмент может быть полезно при диагностике полного жизненного цикла объекта и всех его сохраняемых отсчетов.