Если у меня есть что-то вроде UILabel, связанного с файлом xib, нужно ли мне освобождать его при освобождении моего представления? Причина, по которой я спрашиваю, заключается в том, что я не распределяю его, что заставляет меня думать, что мне тоже не нужно его выпускать? например (в шапке):
IBOutlet UILabel *lblExample;
в реализации:
....
[lblExample setText:@"whatever"];
....
-(void)dealloc{
[lblExample release];//?????????
}
Вы в некотором смысле выделяете метку, создавая ее в IB.
Что делает IB, так это анализирует ваши IBOutlets и их определение. Если у вас есть переменная класса, которой IB должен присвоить ссылку на какой-то объект, IB отправит за вас сообщение о сохранении этому объекту.
Если вы используете свойства, IB будет использовать свойство, которое вы должны установить, и не будет явно сохранять значение. Таким образом, вы обычно отмечаете свойства IBOutlet как сохраненные:
@property (nonatomic, retain) UILabel *lblExample;
Таким образом, в случае эфира (используя свойства или нет) вы должны вызвать release в своем dealloc.
Это не так. Если вы не используете свойства (или реализуете свои собственные методы доступа), то, следует ли вам выпускать, зависит от того, на какой платформе вы находитесь и каков ваш суперкласс. Например, если вы наследуете от NSWindowController, вы не освобождаете.
Я нашел то, что искал, в документации Apple. Короче говоря, вы можете настроить свои объекты как свойства, которые вы освобождаете и сохраняете (или просто @property, @synthesize), но вам не нужно делать такие вещи, как UILabels:
Любой IBOutlet, который является подвидом основного представления вашего Nib, не нужно освобождать, потому что им будет отправлено сообщение автозапуска при создании объекта. Единственные IBOutlet, которые вам нужно выпустить в свой dealloc, - это объекты верхнего уровня, такие как контроллеры или другие NSObject. Все это упоминается в документе Apple, ссылка на который приведена выше.
На самом деле это неправильно. Следует ли вам отправлять объектам верхнего уровня сообщение о выпуске, зависит от того, какую платформу вы используете и от какого класса наследуется ваш владелец файла. Например, если он наследуется от NSWindowController, вам не нужно их освобождать.
Если вы следуете тому, что сейчас считается передовой практикой, вы освобождаете свойства выхода должен, потому что вы должны были сохранить их в установленном аксессоре:
@interface MyController : MySuperclass {
Control *uiElement;
}
@property (nonatomic, retain) IBOutlet Control *uiElement;
@end
@implementation MyController
@synthesize uiElement;
- (void)dealloc {
[uiElement release];
[super dealloc];
}
@end
Преимущество этого подхода состоит в том, что он делает семантику управления памятью явной и понятной, и он работает согласованно на всех платформах для всех файлов пера.
Примечание. Следующие комментарии относятся только к iOS до версии 3.0. В версии 3.0 и более поздних версиях вам следует просто обнулить значения свойств в viewDidUnload.
Однако здесь есть одно соображение: когда ваш контроллер может избавиться от своего пользовательского интерфейса и динамически перезагружать его по запросу (например, если у вас есть контроллер представления, который загружает представление из файла пера, но по запросу - скажем, при нехватке памяти - освобождает его, ожидая, что его можно будет перезагрузить, если представление понадобится снова). В этой ситуации вы хотите убедиться, что при удалении основного представления вы также отказываетесь от владения любыми другими выходами, чтобы их также можно было освободить. Для UIViewController вы можете решить эту проблему, переопределив setView:
следующим образом:
- (void)setView:(UIView *)newView {
if (newView == nil) {
self.uiElement = nil;
}
[super setView:aView];
}
К сожалению, здесь возникает еще одна проблема. Поскольку UIViewController в настоящее время реализует свой метод dealloc
с использованием метода доступа setView:
(а не просто освобождает переменную напрямую), self.anOutlet = nil
будет вызываться в dealloc
, а также в ответ на предупреждение памяти ... Это приведет к сбою в dealloc
.
Чтобы исправить это, убедитесь, что переменные выхода также установлены на nil
в dealloc
:
- (void)dealloc {
// release outlets and set variables to nil
[anOutlet release], anOutlet = nil;
[super dealloc];
}
Если у нас есть свойство сохранения, нельзя ли упростить его, просто сказав self.uiElement = nil; во всех местах, которые мы хотим освободить, поскольку это свойство сохранения, оно должно фактически освободить его должным образом, а также без проблем установить для него значение nil - одно из преимуществ сохранения свойств.
Обычно вы делаете self.uiElement = nil;
в viewDidUnload
, но не в setView:
. И было бы понятнее просто вызвать self.anOutlet = nil;
в dealloc.
Вы не должны вызывать self.anOutlet = nil; в освобождении. Вызывать методы доступа в dealloc - плохая практика.
Я полностью не согласен с тем, что «вызывать методы доступа в dealloc - плохая практика». Я делаю это постоянно, это делает код в миллиард раз чище. У вас есть ссылка на это?
@Wil Shipley: Некоторые документы Apple не рекомендуют использовать аксессоры в методах init и dealloc. Например: developer.apple.com/library/mac/#documentation/Cocoa/Concept ual /… - AFAICT, в основном сеттеры могут (и в KVO имеют) иметь побочные эффекты, помимо простой установки переменной, и если вы запускаете уведомления KVO, вы можете в конечном итоге сказать людям, чтобы они отправляли сообщения объекта после его освобождения.
Это предполагает, что он использует свойства, в которых нет необходимости, если доступ к элементам не будет осуществляться извне объекта.
В
[anOutlet release], anOutlet = nil;
Часть будет совершенно излишней, если вы правильно написали setView :.
На самом деле, насколько я понимаю, это изменилось в версии 3.0 и более поздних версиях. Теперь у нас есть -viewDidUnload, и именно здесь мы выпускаем аксессоры.
Если вы не отпустите его при освобождении, это увеличит объем памяти.
Если вы устанавливаете IBOutlet не как свойство, а просто как переменную экземпляра, вы все равно должны его освободить. Это связано с тем, что при initWithNib память будет выделена для всех IBOutlets. Так что это один из особых случаев, который вы должны освободить, даже если вы не сохранили или не распределили память в коде.
@Soeren: Я уже прочитал эту статью и понял ее содержание. Мой вопрос касался объектов, созданных на IB xib, которые он не охватывает. Например: на самом деле я никогда не создаю и не присваиваю ярлык, все это делает магия IB. Итак, что мне нужно знать, очень просто: нужно ли мне его выпустить?