Встроенные объекты Cocoa принимают владение передаваемых им объектов, сохраняя их, если считают это целесообразным.

Такое сохранение, разумеется, уравновешивается последующим освобождением из памяти. На самом деле это настолько общее явление, что если объект Cocoa не собирается сохранять передаваемый ему объект, то об этом специально упоминается в документации. Особенно это касается коллекций типа NSArray или NSDictionary (подробнее о классах коллекций см. в главе 10).

Объект вряд ли может стать элементом коллекции, если он может в любой момент прекратить свое существование. Следовательно, когда элемент вводится в коллекцию, владение этим объектом подтверждается в ней его сохранением, а после этого коллекция действует как вполне корректный владелец объекта. Так, если это изменяемая коллекция, то при удалении из нее элемента последний освобождается из памяти. Если же объект коллекции прекращает свое существование, то из памяти освобождаются все ее элементы. (Если прежний элемент,

освобожденный коллекцией из памяти, нигде больше не хранится, то он прекращает свое существование.)

До появления механизма ARC удаление объекта из измененяемой коллекции таило в себе потенциальную западню. Рассмотрим следующий фрагмент кода:

NSString* s = myMutableArray[0] ;

[myMutableArray removeObjectAtlndex: 0];

// неудачная идея в коде, не поддерживающем механизм ARC!

Как только что пояснялось, когда объект удаляется из изменяемой коллекции, он освобождается этой коллекцией из памяти. Поэтому во второй строке предыдущего фрагмента кода происходит неявное освобождение объекта из памяти, который прежде хранился в нулевом элементе коллекции типа myMutableArray. Если это приводит к уменьшению подсчета сохраняемых ссылок на объект до нуля, то такой объект уничтожается. Тогда указатель s станет висячим, а впоследствии в прикладном коде может произойти сбой при попытке воспользоваться этим указателем как символьной строкой. Следовательно, до появления механизма ARC приходилось запоминать факт сохранения любого объекта, извлеченного из коллекции, прежде чем выполнить над ним любую операции, способную привести к его разрушению, как показано в примере 12.2.

 

Пример 12.2. Гарантирование сохранности элементов коллекции в коде, не поддерживающем механизм ARC

NSString* s = myMutableArray[0];

[s retain]; // в этом коде механизм ARC не поддерживается [myMutableArray removeObjectAtlndex: 0] ;

Разумеется, при таком управлении памятью, выделяемой под интересующий объект, после подтверждения своих прав на владение им необходимо также принять меры к его освобождению впоследствии, иначе произойдет утечка объекта из памяти. Тем не менее тот же самый код идеально работает и в том случае, если действует механизм ARC, как показано ниже.

NSString* s = myMutableArray[0];

[myMutableArray removeObjectAtlndex: 0];

// этот код вполне работоспособен и тогда, когда действует механизм ARC

Дело в том, что, как упоминалось выш;, механизм ARC изначально действует чрезвычайно консервативно. Как и в примере 12.1, механизм ARC сохраняет объект при его присваивании, и поэтому нетрудно представить, что этот механизм будет действовать по сценарию, приведенному в примере 12.3.

 

Пример 12.3. Возможный сценарий гарантируемой механизмом ARC сохранности элемента коллекции

NSString* s = nil;

// сохранить значение при его присваивании, освободить предыдущее значение id temp = s; s = myMutableArray[0];

[s retain];

[temp release]; // не возымеет никакого действия, т.к. это пустое значение,

//а следующий шаг можно уже сделать без опаски [myMutableArray removeObjectAtlndex: 0];

// ... ив дальнейшем ...

[s release]; s = nil;

Оказывается, это именно то, что и нужно! К тому моменту, когда дело дойдет до вызова метода removeObjectAtlndex:, подсчет сохраняемых ссылок на объект, полученный из массива, окажется увеличенным, поддерживая существование объекта таким же образом, как и в коде без механизма ARC из примера 12.2.


 

 

 

Добавить комментарий