При создании нового проекта и выборе шаблона приложения в среде Xcode 5 для этого проекта по умолчанию применяется механизм ARC. Это, среди прочего, означает следующее.

 

  • Параметр Objective-C Automatic Reference Counting (clang_enable_objc_arc) настройки режима построения в компиляторе LLVM принимает логическое значение YES.
  • Операторы retain или release отсутствуют в файлах шаблона проекта с расширением .т.
  • Любой код, автоматически вводимый впоследствии в среде Xcode, например, при формировании свойства путем перетаскивания при нажатой клавише <Control> из nib-файла в прикладной код, соответствует соглашениям, принятым в механизме ARC.

Существующий проект, не поддерживающий механизм ARC, можно также привести в соответствие с этим механизмом. С этой целью выберите в среде Xcode команду меню Edit^RefactorOConvert to Objective-C ARC, которая поможет внести необходимые изменения в код. Принимать механизм ARC для всего проекта совсем не обязательно. Так, если имеется старый код, несовместимый с механизмом ARC и, возможно, написанный кем-то другим, его, возможно, потребуется внедрить в проект, поддерживающий механизм ARC, не внося существенных изменений в код, несовместимый с этим механизмом. Для этого сосредоточьте весь код, несовместимый с механизмом ARC, в отдельных файлах и для каждого из этих файлов отредактируйте цель, перейдите на вкладку Build Phases (Стадии построения), дважды щелкните на листинге из файла с кодом, несовместимым с механизмом ARC, в разделе Compile Sources и наберите -fno-objc-arc в текстовом поле, чтобы ввести эту директиву в столбец Compiler Flags.

 

 

На самом деле механизм ARC является средством LLVM 3.0 или более поздней версии этого компилятора и одной из главных целей его разработки. За более полной информацией по данному вопросу обращайтесь по адресу http://clang.llvm.org/docs/AutomaticReferenceCounting.html.

 

В процессе компиляции файла с расширением .тис учетом механизма ARC компилятор будет интерпретировать явные команды retain и release как ошибку, а вместо них вставит подспудно свои команды, выполняющие те же самые функции, что и команды retain и release. В итоге прикладной код переводится в режим ручного управления памятью в соответствии с описанными ранее принципами и золотым правилом. Но автором кода ручного управления памятью является компилятор, а сам этот код невидим, хотя его и можно при желании прочитать на уровне языка ассемблера.

Механизм ARC вставляет команды retain и release на двух стадиях.

  1. Механизм ARC ведет себя очень консервативно и при малейшем сомнении сохраняет, а затем освобождает объекты из памяти. По существу, этот механизм сохраняет объекты при всяком стечении обстоятельств, которое может иметь малейшие последствия для управления памятью. В частности, он сохраняет объект, когда последний передается в качестве аргумента, присваивается переменной и т.д. Он может даже вставлять временные переменные, чтобы достаточно рано обратиться к объекту и иметь возможность сохранить его. Но, конечно, он и освобождает объект согласованно. Это означает, что по завершении каждой стадии управление памятью совершается технически корректно. Один объект может сохраняться и освобождаться намного чаще, чем при использовании команд retain и release вручную, но, по крайней мере, можно быть уверенным в том, что висячие указатели и утечки объектов из памяти не возникнут.
  2. Механизм ARC выполняет оптимизацию, удаляя столько пар команд retain и release из каждого объекта, сколько можно, обеспечивая в то же время надежность с точки зрения фактического поведения программы. Это означает, что по завершении второй стадии управление памятью по-прежнему совершается не только технически корректно, но и эффективно.

Рассмотрим в качестве примера следующий код:

- (void) myMethod {

NSArray* myArray = [NSArray array];

NSArray* myOtherArray = myArray;

}

Для выполнения этого фрагмента кода дополнительный код управления памятью на самом деле не требуется по причинам, рассматриваемым в следующем разделе. Даже если не применять механизм ARC, то вводить команды retain и release в этот код не нужно. Но нетрудно представить, что на первой стадии выполнения этого кода механизм ARC будет действовать весьма консервативно, гарантируя, что переменная будет иметь пустое значение nil или же указывать на объект, сохраняя каждое присваиваемое ей значение и в то же время освобождая каждое присвоенное ей прежде значение, на которое она указывала, при условии, что это значение было ранее сохранено при его присваивании данной переменной. Таким образом, нетрудно представить, хотя это вряд ли будет совершенно правильно, что рассматриваемый здесь код будет сначала скомпилирован с учетом действия механизма ARC в эквивалентный код, приведенный в примере 12.1.

 

Пример 12.1. Возможный сценарий консервативного управления памятью с помощью механизма ARC

- (void) myMethod {

// сделать пустыми все указатели на новые объекты NSArray* myArray = nil;

// сохранить при присваивании, освободить предыдущее значение id tempi = myArray; myArray = [NSArray array];

[myArray retain];

[tempi release]; // (no effect, it's nil)

// сделать пустыми все указатели на новые объекты NSArray* myOtherArray = nil;

// сохранить при присваивании, освободить предыдущее значение id temp2 = myOtherArray; myOtherArray = myArray;

[myOtherArray retain];

[temp2 release]; // (no effect, it's nil)

// завершить метод, сохранить равновесие в локальных переменных // сделать пустыми все указатели путем освобождения из памяти, когда // все остальное останется уравновешенным [myArray release]; myArray = nil;

[myOtherArray release]; myOtherArray = nil;

}

Далее вступает в действие оптимизатор ARC, уменьшая объем выполняемой работы. Например, он может обнаружить, что переменные myArray и myOtherArray превращаются в указатели на тот же самый объект, и поэтому он может удалить некоторые промежуточные команды сохранения и освобождения из памяти. Кроме того, оптимизатор ARC может обнаружить, что посылать команду release пустому значению nil не нужно. Но команды сохранения и освобождения из памяти настолько эффективны, когда действует механизм ARC, что вряд ли будет иметь большое значение, если оптимизатор не удалит любые промежуточные команды сохранения и освобождения из памяти.

Намного большее значение имеет уравновешивание ручного управления памятью, чем согласованное выполнение команд retain и release. В частности, как упоминалось ранее, команды alloc и сору порождают объекты, подсчет сохраняемых ссылок которых уже увеличен, и поэтому они также должны быть уравновешены командой release. Для того чтобы подчиняться этой части правил управления памятью в среде Cocoa, механизм ARC прибегает к предположениям относительно именования методов.

В частности, когда в прикладном коде получается объект в качестве значения, возвращаемого в результате вызова метода, механизм ARC ищет начальное слово (или несколько слов) в имени метода, имеющем смешанное написание. (Термином смешанное написание описывается составное слово, отдельные слова которого начинаются с прописной буквы, например: СмешанноеНаписание.) Если начальным словом в имени метода оказывается alloc, init, new, сору или mutableCopy, то в механизме ARC предполагается, что объект возвращается методом вместе с увеличенным подсчетом сохраняемых ссылок, который должен быть уравновешен соответствующей командой release.

Так, если бы в приведенном выше примере в результате вызова [NSArray new] вместо вызова [NSArray array] был получен массив, то механизму ARC стало бы известно, что потребуется дополнительное освобождение из памяти, чтобы уравновесить увеличенный подсчет сохраняемых ссылок на объект, возвращаемый из метода, имя которого начинается на new.

В связи с этим на вас возлагается ответственность не именовать свои методы таким образом, чтобы вызывать своего рода сигнал тревоги у механизма ARC. Поэтому проще всего не начинать имена любых методов с alloc, init (если только речь не идет о написании инициализатора), new, сору или mutableCopy. Употребление этих слов в именах методов вряд ли нанесет много вреда, но все же лучше не рисковать, но подчинить, насколько это возможно, механизм ARC соглашениям об именовании. (Из этого затруднительного положения имеются и другие пути выхода, если неверно именованные методы нельзя никак изменить, но здесь они не рассматриваются.)


 

 

 

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