Освобождение IBOutlets и переменных экземпляра

#objective-c #cocoa-touch #memory-management #properties #iboutlet

#objective-c #cocoa-touch #управление памятью #свойства #iboutlet

Вопрос:

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

В моем заголовочном файле я объявляю ссылку на IBOutlet следующим образом:

 @interface Test : UIViewController {
    UIButton *_loginBtn;
}

@property (nonatomic, retain) IBOutlet UIButton *loginBtn;
  

И в файле реализации я связываю переменную экземпляра со свойством и освобождаю ее следующим образом:

 @implementation Test

@synthesize loginBtn = _loginBtn;

...

- (void) dealloc {
    [_loginBtn release];
    self.loginBtn = nil;

    [super dealloc];
}

- (void) viewDidUnLoad {
    [_loginBtn release];
    self.loginBtn = nil;

    [super viewDidUnLoad];
}
  

Правильно ли я определил освобождение переменной экземпляра и присвоил свойству значение nil и сделал это в обоих методах viewDidUnLoad and dealloc ?

Комментарии:

1. На самом деле я бы ожидал, что [_loginBtn release]; в сочетании с self.loginBtn = nil; произойдет сбой. Первый освободит значение, но оставит его установленным. Затем второй попытается снова освободить значение, установив для него значение nil. Это было бы двойным выпуском.

Ответ №1:

В in нет необходимости self.loginBtn = nil; dealloc , предыдущая строка освободила его. Лучше не использовать свойство для его освобождения в dealloc. Причина освобождения vs для установки свойства в nil заключается в том, что установщик является вызовом метода, а класс находится в процессе разрушения, и ситуация может быть нестабильной.

При viewDidUnLoad освобождении любых свойств, IBOutlet с self.theOutlet = nil; которыми они связаны, в данном случае _loginBtn release]; они не нужны и являются избыточными. Также освободите любые другие объекты, которые вы можете легко воссоздать.

Если используются свойства, они должны использоваться для всех обращений в классе с двумя исключениями: init и dealloc. В обоих этих случаях класс частично завершен. В этих двух случаях лучше всего использовать ivar непосредственно в init (при необходимости) и release в dealloc .

Комментарии:

1. должен ли я просто устанавливать IBOutlets на nil в viewDidUnload или я также должен устанавливать такие свойства, как массивы, на nil (опять же в viewDidUnload)?

2. Основная проблема здесь — предупреждения о памяти и памяти. При предупреждении о памяти система может выгружать представления, которые не отображаются, чтобы освободить необходимую память. Проще всего установить для IBOutlets значение nil, освободив их, система повторно загрузит их при повторной загрузке представления. Если у вас есть объекты, которые вы можете легко воссоздать, рассмотрите возможность их освобождения, вам придется воссоздать их в viewDidLoad . Чем больше вы помогаете ситуации с памятью, тем дольше ваше приложение живет в фоновом режиме, ожидая повторного запуска.

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

Ответ №2:

Нет, это неверно. Сначала отпуская _loginBtn, а затем устанавливая для свойства значение nil, вы освобождаете экземпляр дважды. Правильный способ сделать это — освободить _loginBtn, а затем установить _loginBtn равным нулю.

Комментарии:

1. Добро пожаловать. Одно замечание, поскольку я не могу прокомментировать другой ответ. Во многих случаях предпочтительнее вызывать release вместо присвоения nil свойству, поскольку освобождение в свойстве реализуется с использованием автоматического освобождения, что задерживает освобождение и приводит к накладным расходам. Я бы выбрал release, а затем установил local равным нулю, чтобы избежать несчастных случаев с последующими частями метода dealloc с использованием свойства.