Статьи

Основы iPhone: управление памятью

Одним из главных источников путаницы для новых разработчиков iPhone является управление памятью. Если вы привыкли использовать удобные языки сценариев для сборки мусора, вам может быть интересно, почему управление памятью даже необходимо. Хотя Cocoa поддерживает сборку мусора, для телефонной платформы это было слишком дорого. Поэтому для разработчиков важно знать, как правильно распределять и освобождать объекты.

Следуя некоторым простым рекомендациям, вы можете избежать большинства проблем с управлением памятью.

1. Если вы выделяете объект, вы должны освободить его, когда закончите.

Когда вы выделяете объект, вы «владеете» этим объектом и несете ответственность за его освобождение по окончании использования:

Widget* widget = [[Widget alloc] init]; // Do something with widget... [widget release]; 

Вы можете думать об release как о том, что вы отказываетесь от владения этим объектом , а не уничтожаете его . За кулисами Cocoa выполняет подсчет ссылок, чтобы отслеживать владельца. Если никто не претендует на право собственности, объект будет уничтожен, а память, которую он занимал, будет возвращена.

2. Если вы не разместили объект напрямую, вы не должны освобождать его.

Как только вы получаете навык release , возникает соблазн выпустить объекты, когда вы не должны. Типичным примером является использование фабричных методов:

 NSString* label = [NSString stringWithFormat:@"Title: %@", widget.title]; // Do something with label [label release] // Whoops, incorrect. 

В этом примере был создан новый строковый объект, но мы не распределили его и не владеем им. Поэтому мы не должны вызывать release здесь — это может вызвать перевыпуск, который может привести к сбою вашего приложения.

совет: как этот объект выпущен?

За кулисами NSString вызывал autorelease для строки перед возвратом, что мы рассмотрим autorelease .

3. Если вам нужен объект, вы должны retain его (и release когда закончите).

Это правило применяется, когда мы получаем объект, созданный кем-то другим. Например, рассмотрим метод установки:

 - (void)setName:(NSString*)newName; { [newName retain]; // we need the new string object. [name release]; // we don't need the old string any more. name = newName; } 

retain сигналы о том, что мы заявляем о праве собственности на объект; он не будет уничтожен, когда первоначальный владелец выпустит его. Но теперь, когда мы владеем объектом, мы должны освободить его, когда он нам больше не нужен. Под капотом retain и release обновление счетчика ссылок объекта, увеличивая и уменьшая соответственно.

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

 UIButton* button = [[UIButton alloc] initWithFrame:myFrame]; [self.view addSubview:button] // Here we can assume that view // has retained button, [button release] // we can safely release it. 

Другой распространенный пример возникает, когда мы используем объекты коллекции, которые сохраняют добавленные к ним объекты:

 NSMutableArray* widgetList = [[NSMutableArray alloc] init]; // ... Widget* widget = [[Widget alloc] init]; [widgetList addObject:widget]; // retains widget [widget release]; // we can release widget //... [widgetList release] // objects in collection will be released. 

4. Если вы создаете объект и не сохраняете контроль над ним, используйте autorelease .

Скажем, вы хотите создать свой собственный фабричный метод для Widget. Здесь мы создаем новый объект Widget и возвращаем его из метода класса:

 + (Widget*)createBetterWidget { Widget* widget = [[Widget alloc] init]; [widget setAwesome:11]; return [widget autorelease]; } 

Мы по-прежнему несем ответственность за освобождение объекта, поэтому мы вызываем autorelease перед его возвратом. autorelease сообщает, что объект должен быть освобожден «в конце концов». Объект добавляется в пул, который очищается в конце цикла выполнения приложения.

Может показаться заманчивым автоматическое высвобождение всего в качестве решения для управления памятью, однако это не рекомендуется, поскольку у вашего приложения может быть нехватка памяти до того, как пул автоматического высвобождения будет исчерпан.

Наилучший подход заключается в простом, однозначном подходе к распределению и освобождению объектов. Следуйте этим простым правилам, и вы будете на пути к созданию безошибочного и эффективного кода.

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

Изображение предоставлено: Dezeen