IOS. Каков наилучший способ управления памятью для IBOutlets?

Я просматривал документы 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 будет увеличен дважды: один раз при загрузке ниба и в другое время, когда свойство будет установлено? И не было бы лучше установить эти свойства на нуль, а не на освобождение в dealloc?

Ответ 1

Apple docs говорит, что мы должны сохранить свойства для iOS.
Отпущенные розетки должны отпускаться, а nil - в dealloc и viewDidUnload.

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

Там очень полезная статья Джеффа ЛаМархе по этой теме: Outlets, Cocoa vs. Cocoa Touch.

Ответ 2

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

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

Ответ 3

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

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

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

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

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

Ответ 4

Я предполагаю вам @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 скажут вам, чтобы пойти на что;)

Ответ 5

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

ну, код, который вы опубликовали, прав, как есть.

когда вы используете:

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

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

yourMapViewController.mapView = someMapView; // from out

// or

self.mapView = someMapView; // from in

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

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

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