Одним из главных источников путаницы для новых разработчиков 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