ПРОГРАММИРОВАНИЕ ПОД IPHONE, IPAD OBJECTIVE-C Часть 1

Automatic Reference Counting (ARC)

Automatic Reference Counting (ARC) —  это механизм автоматического подсчета ссылок, который перекладывает управление памятью на компилятор. Теперь вам не нужно релизить объекты или освобождать память, что значительно упрощает процесс разработки и снижает риск создания утечек памяти. Компилятор полностью «понимает» когда объект создается, а когда его нужно уничтожить, таким образом, приложения работают так же быстро как и раньше.

Изначально ARC был разработан для упрощения изучения Objective-C. Управление памятью было самым сложным этапом разработки для большинства начинающих программистов. Чтобы исправить эту ситуацию, Apple разработали систему автоматического подсчета ссылок. Фактически, это сильно доработаный анализатор, но теперь он не только ищет ошибки в управлении памятью, то и исправляет их за вас (что вполне логично). Даже более того, ARC запрещает создавать утечки памяти. Если раньше вы могли создать объект и не очистить память — компилятор это пропускал. То теперь программы с утечками просто не будут компилироваться. Хотя, я уверен, что найдутся народные умельцы, которые смогут выдать перлы достойные удивления разработчиков ARC.

ARC доступен, начиная с Xcode 4.2 (iOS 4.3.3), и только с компилятором Apple LLVM compiler:

Кроме этого, следует отметить настройку с аналогичным названием:

При этом слудет помнить, что изменение этой опции в существующем проекте может повлечь за собой большое число ошибок. Это связано с тем, что ARC перекладывает на себя процесс управления памятью. Это похоже на самолет с автопилотом. Управлять таким самолетом может либо пилот, либо компьютер, но никак одновременно. Соответственно — это накладывает некоторые ограничения на ваш код. А именно, вы не сможете посылать сообщения retain-release-autorelease объектам.

Но Apple не оставил нас на едине со старым кодом. Вы можете конвертировать ваши проекты использую пункты меню Edit -> Refactor… -> Convert to Objective-C ARC… Вам предоставляется возможность пошагово преобразовать код.

От теории к практике

Для начала я предлагаю вспомнить правила работы с памятью. Они уже были написаны в уроке Управление памятью (Memory management). С них нам нужно самое главное правило: если мы посылаем объекту alloc, new, copy, или retain мы должны компенсировать это используя release или autorelease.

То есть, если мы раньше писали примерно так:

<code data-result="[object Object]">MYObject *object = [MYObject new];
[object doSomething];</code>

то в результате у нас выполнялась функция doSomething и мы получали утечку памяти.

Теперь компилятор «видит» несбалансированный new и преобразует код следующим образом:

<code data-result="[object Object]">MYObject *object = [MYObject new];
[object doSomething];
[object release];</code>

На самом деле, компилятор не посылает сообщение release нашему объекту. Он просто вставляет вызов специальной runtime-функции.

Кроме этого, ARC автоматически создает и заполняет метод dealloc для всех классов для освобождения всех переменных его экземпляра. Но вы так же можете в ручную написать этот метод (иногда необходимо выполнить определенный код в момент удаления объекта). Но освобождать переменные экземпляра класса вы уже не сможете, так же как и вставить [super dealloc] (ARC сделает это за вас).

Рассмотрим конкретный пример. Если раньше вам приходилось писать так:

<code data-result="[object Object]">- (void)dealloc {
    self.list = nil;
    self.name = nil;

    [tickTimer invalidate];

    [super dealloc];
}</code>

То теперь достаточно:

<code data-result="[object Object]">- (void)dealloc {
    [tickTimer invalidate];
}</code>

В случае, если в методе dealloc нет необходимости выполнять какой-то код или вызывать другую функцию — его можно вообще не добавлять в класс.

Атрибуты свойств

При указании атрибутов свойств вводятся новые объявления. Такие как weak и strong. Посмотрим на примере кода как это работает:

<code data-result="[object Object]">// Следующее объявление является синонимом: @property(retain) MyClass *myObject;
@property(strong) MyClass *myObject;

// Следующее объявление является синонимом для "@property(assign) MyClass *myObject;"
// кроме этого, в случае освобождения myObject,
// ему автоматически присваивается значение nil.
@property(weak) MyClass *myObject;</code>

Возможные префиксы для создания ссылок:

<code data-result="[object Object]">__strong
__weak
__unsafe_unretained
__autoreleasing</code>
  • __strong по умолчанию.
  • __weak создает обнуляемую слабую ссылку на объект
  • __unsafe_unretained слабая не обнуляемая ссылка (ее следует обнулять вручную, после того, как объект, на который она указывает, был уничтожен)
  • __autoreleasing для обозначения аргументов, которые передаются по ссылке (id *) и autoreleased при возвращении.

Подведем итоги

Если мы создаем объект — нам не нужно его релизить.

Если раньше мы писали так:

<code data-result="[object Object]">@interface ViewController : UIViewController {
    UIImageView *logo;
    NSArray *objectsList;
    NSInteger index;
}

@property (nonatomic, retain) IBOutlet UIImageView *logo;
@property (nonatomic, retain) NSArray *objectsList;
@property (nonatomic, assign) NSInteger index;

@end</code>

теперь это должно выглядеть так:

<code data-result="[object Object]">@interface ViewController : UIViewController

@property (nonatomic, strong) IBOutlet UIImageView *logo;
@property (nonatomic, strong) NSArray *objectsList;
@property (nonatomic, assign) NSInteger index;

@end</code>

В реализации класса мы так же синтезируем методы доступа, а метод dealloc объявляем только в том случае, если в нем нужно выполнить какой-то код. И в случае с делегатом в свойствах следует указывать unsafe_unretained.

Если по какой-то причине вам понадобилось использовать класс без поддрежки ARC в проекте с его поддержкой. И по какой-то причине вы не хотите его конвертировать. На помощь вам прийдет специальный флаг компилятора -fno-objc-arc. Для его установки выберите таргет вашего проекта, затем перейдите в Build Phases, раскройте список Compile Sources, найдите в списке классов нужны и кликните по нем двойным щелчком. После добавления комманды должен получиться примерно следующий результат:

Пока что это все. Если будут вопросы — смело задавайте в комментариях и я буду дополнять статью.

Comments are closed.