Главная » iPhone, Objective-C, Программирование для iOS и MacOS » Для любознательных: ручной подсчет ссылок и история ARC Objective-C

0

Как упоминалось в начале главы 19, до появления в Objective-C механизма автоматического подсчета ссылок ARC (Automatic Rеfегепсе Counting) использовался ручной подсчет ссылок, при котором владельцы изменялись только при явной отправке объекту сообщения, уменьшавшего или увеличивавшего счетчик ссылок.

[anObject release]; // anObject теряет владельца [anObject retain]; // anObject получает владельца

Подобные вызовы в основном встречаются в методах доступа (retain – при создании нового значения, release – при освобождении старого значения) и в методах dealloc (при освобождении всех ранее захваченных объектов). Метод setHolder: класса Asset в этом случае выглядит примерно так:

-­‐    (void)setHolder:(Employee   *)newEmp

{

[newEmp retain]; [holder release]; holder = newEmp;

}

А вот как будет выглядеть метод dealloc:

-­‐    (void)dealloc

{

[label release]; [holder release]; [super dealloc];

}

Как насчет метода description? Он создает и возвращает строку. Должен ли класс Asset заявлять на нее права владельца? Нет, это бессмысленно – ведь ресурс не удерживает созданную строку. Отправляя объекту сообщение autorelease, вы помечаете его для отправки release в будущем. До появления ARC метод description класса Asset выглядел бы так:

-­‐   (NSString  *)description

{

NSString *result = [[NSString alloc] initWithFormat:@"<%@: $%d >",

[self label], [self resaleValue]];

[result autorelease]; return result;

}

Когда   отправляется   сообщение   release?   При   сбросе   текущего   пула

autorelease:

// Создание пула autorelease

NSAutoreleasePool *arp = [[NSAutoreleasePool alloc] init]; Asset *asset = [[Asset alloc] init];

NSString *d = [asset description];

// строка, на которую указывает d, находится в пуле autorelease [arp drain]; // Строке отправляется сообщение release

ARC использует пул autorelease автоматически, но за создание и сброс пула отвечаете вы. С появлением ARC также появился новый синтаксис создания пула autorelease. Приведенный выше код теперь выглядит следующим образом:

// Создание пула autorelease

@autoreleasepool {

Asset *asset = [[Asset alloc] init];

NSString *d = [asset description];

// строка, на которую указывает d, находится в пуле autorelease

}// Сброс пула

Правила подсчета ссылок

Существует стандартный набор соглашений по работе с памятью, которые соблюдаются всеми программистами Objective-C. Если вы используете ARC, то эти соглашения автоматически выполняются за вас.

В этих правилах словом «вы» я обозначаю «экземпляр класса, с которым вы работаете в настоящий момент». Такая точка зрения весьма полезна: представьте, что вы – объект, над которым вы работаете в настоящий момент. Таким образом, фраза

«Если вы  становитесь владельцем  строки, она  не будет  уничтожена»  в действительности означает «Если экземпляр класса, над которым вы работаете, становится владельцем строки, она не будет уничтожена».

Итак, правила (в круглых скобках описаны подробности реализации).

Если вы создаете объект методом, имя которого начинается с аlloc или new или содержит сору, то вы становитесь его владельцем. (То есть предполагается, что у нового объекта счетчик ссылок равен 1 и он не находится в пуле autorelease.) Вы отвечаете за уничтожение объекта, когда он станет ненужным. Примеры часто используемых методов, которые делают вас владельцем созданного объекта: alloc (за вызовом которого всегда следует вызов init), сору и mutаblеСору.

•  Если объект был создан любыми другими средствами, вы не являегесь его владельцем (То есть следует полагать, что его счетчик ссылок равен 1 и он уже находится в пуле autorelease – а следовательно, обреченна уничтожение, если только у него не появится новый владелец до сброса пула autorelease.)

•  Если вы не являетесь владельцем объекта, но хотите, чтобы он продолжая существовать, станьте его владельцем, отправив ему сообщение retain (что приводит к увеличению счетчика ссылок).

•  Если вы являетесь владельцем объекта и он вам больше не нужен, отправьте ему сообщение release или autorelease. (Сообщение release уменьшает счетчик ссылок немедленно, autorelease приводит к отправке сообщения release при сбросе пула.)

•  Пока у объекта остается хотя бы один владелец, он продолжит существовать, (Когда счетчик ссылок уменьшится до нуля, объекту отправляется сообщение dealloc.)

Чтобы лучше разобраться в управлении памятью, полезно рассматривать происходящее с локальной точки зрения. Классу Asset ничего не нужно знать о других объектах, для которых также существенно содержимое его метки. При условии, что экземпляр Asset назначает себя владельцем объектов, которые он хочет удержать в памяти, проблем не будет. Начинающие программисты иногда совершают ошибку, пытаясь самостоятельно вести учет ссылок на все объекты в приложении. Не делайте этого.

Если вы соблюдаете эти правила и всегда мыслите локальными категориями

класса, вам никогда не придется беспокоиться о том, как остальные части приложении работают с объектом.

После знакомства с концепцией владения становится ясно, почему необходимо отправлять autorelease в методе description для строки: объект работника создает строку, но не хочет становиться ее владельцем.

Источник: Аарон Хилегас, «Objective-C. Программирование для iOS и MacOS», 2012 г.

По теме:

  • Комментарии