![](https://habrastorage.org/storage/970f6cfa/3507de4e/bcf2b674/8c739f0f.jpg)
К проблемам с памятью можно отнести утечки и так называемых «зомби». Приложение, в котором творится бардак с памятью, становится нестабильным, в нём появляется целый букет странностей, начинаяя с пропадания некоторых элементов интерфейса и заканчивая падениями.
Для начала давайте определимся, что такое утечки. Утечки — выделенные, но не освобождённые области памяти, на которые нет указателя. Всё это выглядит достаточно несерьёзно, у iPhone куча оперативной памяти, а обычное приложение занимает в лучшем случае 2 Мб. На деле всё не так радужно: приложение может использовать до 3мб, а дальше начинают возникать memory warning, соответственно, ОС пытается освободить те области, которые считает «ненужными». Попросту говоря, удаляет невидимые в данный момент элементы интерфейса, а это не только некрасиво, но и может привести к падению приложения. «Зомби» — уже освобождённые (убитые) области памяти, к которым пытается обратиться программа, что также приводит к падению приложения.
В iOS есть сборщик мусора!
Многие (да я и сам этим грешу) часто говорят, что его нет. Но всё же сборщик мусора есть, хоть и весьма примитивный. Принцип управления памятью основан на подсчёте количества ссылок на объект. При выделении памяти под объект их количество устанавливается равным 1, а при достижении 0 память освобождается (выбрасывается мусор). Каждый раз, когда вы хотите использовать объект, вы должны увеличить количество ссылок, а каждый раз, когда он вам становится ненужным — уменьшить.
Есть 4 волшебных слова
Чтобы управлять памятью, нужно запомнить всего 4 слова:
alloc
, copy
, retain
, release
. Давайте поговорим о каждом из них в отдельности: alloc
Выделяет память под объект и увеличивает кол-во ссылок на 1. Использовать его необходимо каждый раз, когда вы создаёте новый объект.
copy
Копирует объект (не указатель). Оставляет неизменным количество ссылок на объект, который мы копируем и увеличивает их количество на новый объект.
retain
Просто увеличивает количество ссылок на объект.
release
Обратная трём вышеперечисленным операция, уменьшает количество ссылок на 1.
И еще кое что
Autorelease
Это немного другая история. Если отправить объекту сообщение
autorelease
, то произойдёт «отложенный» release
. Это нужно для тех случаев, когда вы не сможете по каким либо причинам отправить сообщение release
объекту после действий с ним. Его основное применение — возвращение объектов методами. Любой метод, в названии которого нет alloc
, copy
, retain
, возвращает и должен возвращать «авторелизный» объект. Но почему бы тогда не использовать его везде? Это же так удобно! Удобно, но накладно. Из-за того, что количество ссылок на объект уменьшается не сразу, соответственно, память тоже освобождается не сразу. Тут нас и ждёт подводный камень: у нас всего 3мб, а если мы за раз обрабатываем большой объём данных, появляются те самые memory warning.
Dealloc
Этот метод вызывается при удалении объекта, в нём вы должны сделать release всех переменных, которые использовал объект, и в конце вызвать
dealloc
у родителя.- (void)dealloc {
[model release];
[view release];
[super dealloc];
}
Property
Свойства бывают трёх видов:
assign
, retain
, copy
. Последние два должны быть уже понятны. А первый просто присваивает значение, никак не влияя на количество ссылок на объект. Приведу правильную реализацию сеттеров для каждого типа: //assign
- (void)setList:(List *)list{
_list = list;
}
//retain
- (void)setList:(List *)list{
[_list autorelease];
_list = [list retain];
}
//copy
- (void)setList:(List *)list{
[_list autorelease];
_list = [list copy];
}
Помните, вам не нужно следить за тем, что делает
Property
, вам достаточно уcтановить его, а при необходимости сбросить значение, просто обнулить его. Delegate, курица и яйцо
В процессе работы мы наткнулись на проблему, связанную с тем, что у нас утекало большое число объектов. Выяснилось, что у нас два объекта ретейнили друг-друга и, соответственно, никогда не освобождали память. Это происходило при использовании паттерна делегирования. Был объект, который создавал другой объект и ставил себя его делегатом. А свойство
Delegate
было прописанно как retain
. Ситуацию спасает замена retain
на assign
. Несколько советов напоследок
- Слово release должно приходить сразу после
alloc
,retain
илиcopy
- А слово nil сразу после
release
- Всегда обnilяйте делегатов
- По возможности воздержитесь от
autorelease
- Создавайте объекты именно тогда, когда они вам нужны
- Не злоупотребляйте полями класса
- Static Analysys Tool всё красиво и понятно рисует
- Изредка проверяйте на утечки
Иван Ушаков, программист команды iOS