При создании нового проекта и выборе шаблона приложения в среде Xcode 5 для этого проекта по умолчанию применяется механизм 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 на двух стадиях.
Рассмотрим в качестве примера следующий код:
Для выполнения этого фрагмента кода дополнительный код управления памятью на самом деле не требуется по причинам, рассматриваемым в следующем разделе. Даже если не применять механизм ARC, то вводить команды retain и release в этот код не нужно. Но нетрудно представить, что на первой стадии выполнения этого кода механизм ARC будет действовать весьма консервативно, гарантируя, что переменная будет иметь пустое значение nil или же указывать на объект, сохраняя каждое присваиваемое ей значение и в то же время освобождая каждое присвоенное ей прежде значение, на которое она указывала, при условии, что это значение было ранее сохранено при его присваивании данной переменной. Таким образом, нетрудно представить, хотя это вряд ли будет совершенно правильно, что рассматриваемый здесь код будет сначала скомпилирован с учетом действия механизма ARC в эквивалентный код, приведенный в примере 12.1.
Пример 12.1. Возможный сценарий консервативного управления памятью с помощью механизма ARC
Далее вступает в действие оптимизатор 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 соглашениям об именовании. (Из этого затруднительного положения имеются и другие пути выхода, если неверно именованные методы нельзя никак изменить, но здесь они не рассматриваются.)