iOS - Каков наилучший способ управления памятью для IBOutlets? - PullRequest
10 голосов
/ 08 марта 2011

Я просматривал документы Apple и пример кода, чтобы попытаться определить лучший способ управления памятью для IBOutlets. Я немного запутался, если не сказать больше.

Пример кода CurrentAddress объявляет IBOutlets как свойства:

@interface MapViewController : UIViewController <MKMapViewDelegate, MKReverseGeocoderDelegate>

{
    MKMapView *mapView;
    UIBarButtonItem *getAddressButton;
}
@property (nonatomic, retain) IBOutlet MKMapView *mapView;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *getAddressButton;

Отлично. И они выпущены в dealloc:

- (void)dealloc
{
    [mapView release];
    [getAddressButton release];
    [super dealloc];
}

Теперь эти свойства не должны быть назначены? Потому что при сохранении счетчик хранения IBOutlet будет увеличен вдвое: один раз при загрузке пера и другой раз при установке свойства? И не лучше ли установить эти свойства равными nil вместо того, чтобы выпускать в dealloc?

Ответы [ 5 ]

7 голосов
/ 08 марта 2011

Apple Docs говорит, что мы должны сохранить свойства для iOS.
Оставшиеся розетки должны быть освобождены и nil 'изданы как dealloc и viewDidUnload.

На Mac каждая розетка, которая не сохраняется суперпредставлением, автоматически сохраняется при загрузке пера. Это не так с iOS. Вот почему теоретически допустимо сохранять только выходы, отличные от представлений в иерархии представлений.

Джефф Ламарш (Jeff LaMarche) написал очень полезную статью на эту тему: Outlets, Cocoa vs. Cocoa Touch .

2 голосов
/ 08 марта 2011

Как только загрузчик пера завершает загрузку всего и подключает все IBOutlets, он автоматически освобождает все загруженные объекты.Если ваше свойство IBOutlet было объявлено как assign, то объект, на который он указывает, будет удален в следующий раз при очистке пула автоматического выпуска.

Вы можете установить для свойств значение nil в dealloc вместо непосредственного их освобождения, в результатета же.Следите за тем, чтобы, если вы предоставили собственную реализацию метода установки, вам следует помнить, что некоторые другие члены вашего объекта уже могут быть освобождены.

1 голос
/ 08 марта 2011

Это отличается для MacOSX и iOS.В iOS количество сохранений будет равно двум после загрузки представления и установления пера.

Каждый из этих элементов будет сохраняться один раз представлением и один раз вашим контроллером.Дополнительные элементы в представлении будут сохраняться только только представлением.

Когда ваш контроллер освобождает эти два элемента, их количество сохранений уменьшается до одного.После этого вызывается [super dealloc].UIViewController имеет [view release] в своем значении, поэтому представление освобождается (если оно не сохранено в другом месте или не выпущено ранее).Когда представление освобождается, оно освобождает свои подчиненные представления, и, наконец, элементы полностью освобождаются.

Причина, по которой [освобождение объекта] предпочтительнее в dealloc, заключается в том, что кодирование значения ключа (или ваш собственный код)может привести к запуску дополнительного кода при написании [self setObject: nil].Это может привести к взаимодействию других объектов с вашим контроллером, когда он находится в процессе освобождения.Сеттеры не должны использоваться в методе init по той же причине.

Есть вторая причина просто делать релиз.Оставляя значение и не устанавливая его равным nil, мы заметим, если код ошибочно обращается к этой переменной в нашем объекте позже во время dealloc.Это может помочь выявить ошибки, которые в противном случае будет нелегко отследить.

0 голосов
/ 08 марта 2011

не должны ли эти свойства быть установлены в назначить? Потому что, когда установлен, чтобы сохранить, счет удержания IBOutlet будет увеличивается вдвое: один раз, когда перо загружен и в другой раз, когда свойство установлено

хорошо, код, который вы разместили, верный.

при использовании:

@property (nonatomic, retain) IBOutlet MKMapView *mapView;

вы просто указываете xCode создать метод установки, который будет создавать ваш объект MKMapView и сохранять его при каждом вызове

yourMapViewController.mapView = someMapView; // from out

// or

self.mapView = someMapView; // from in

после этого mapView сохранит увеличение количества +1 и ваш код MapViewController нуждается в этом, потому что теперь вы можете указывать на mapView и управлять им ...

не беспокойтесь о файле пера IB ...

когда вы загружаете UIViewController с пером, в вашем случае класс MapViewController: UIViewController, объекты пера IB будут освобождены, когда вы отпустите MapViewController ... просто заботиться о предметах, которые вы сохраняете ...

0 голосов
/ 08 марта 2011

Я предполагаю, что вы @synthesize эти свойства.Если вы этого не сделаете, вам придется освободить себя вручную.Вы совершенно правы в своем предположении, что если вы продолжите сохранять, когда свойство установлено, вы потеряете память.

Давайте подумаем .... как выглядели свойства раньше, чем мы привыкли @synthesize оператор?

id _propertyName; // the ivar

- (id) propertyName {
  return _propertyName;
}

- (void) setPropertyName:(id)v {
  if (_propertyName) {
    [_propertyName release]; // release the previously retained property
  }
  _propertyName = [v retain]; // retain this one so it doesn't fly away on us
}

Теперь вам не нужно набирать этот материал, потому что @synthesize это круто и генерирует его для вас, он также будет генерировать блоки @synchronized, если вы не укажете что-то какбудучи nonatomic, что тоже довольно рад.

Если вы укажете assign вместо retain, вы получите что-то вроде этого

id _propertyName; // the ivar

- (id) propertyName {
  return _propertyName;
}

- (void) setPropertyName:(id)v {
  _propertyName = v;
}

Это примерно единственноевещь, которую вы МОЖЕТЕ сделать, когда вещи не являются объектами, потому что они являются только значениями (также иногда называемыми типами значений, объекты являются ссылочными типами).Поскольку типы значений не могут быть сохранены, другой тип блока не будет иметь никакого смысла.Попытайтесь создать свойство сохранения с помощью BOOL и посмотрите, что LLVM или GCC скажут вам делать с чем;)

...