Вопрос

Вот обычная практика, которую я часто вижу (в том числе из очень популярной книги для разработчиков iPhone)

В файле .h:

@interface SomeViewController : UIViewController
{
  UIImageView *imgView;
}

Где-то в .m файле:

imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]
applicationFrame]];
[imgView setImage:[UIImage imageNamed:@"someimage.png"]];
[self addSubview:imgView];
[imgView release];

И позже мы видим это ...

- (void) dealloc
{
  [imgView release];
  [super dealloc];

} 

Поскольку у imgView есть соответствующие alloc и release, необходим ли выпуск imgView в dealloc?

Где учитывается imgView, сохраняемый вызовом addSubview?

Это было полезно?

Решение

Да, у этого кода есть проблемы. Он выпускает imgView слишком рано, что потенциально может вызвать сбои в редких случаях сохраняет объект в переменной экземпляра, не сохраняя его, и обычно он работает с управлением памятью неправильно.

Один из правильных способов сделать это:

@interface SomeViewController : UIViewController
{
    UIImageView *imgView;
}
@property (nonatomic, retain) UIImageView *imgView;

И в реализации;

@synthesize imgView;

Где-то в модуле:

//Create a new image view object and store it in a local variable (retain count 1)
UIImageView *newImgView = [[UIImageView alloc] initWithFrame:self.view.bounds];
newImgView.image = [UIImage imageNamed:@"someimage.png"];

//Use our property to store our new image view as an instance variable,
//if an old value of imgView exists, it will be released by generated method,
//and our newImgView gets retained (retain count 2)
self.imgView = newImgView;

//Release local variable, since the new UIImageView is safely stored in the
//imgView instance variable. (retain count 1)
[newImgView release];

//Add the new imgView to main view, it's retain count will be incremented,
//and the UIImageView will remain in memory until it is released by both the
//main view and this controller. (retain count 2)
[self.view addSubview:self.imgView];

И сделка остается прежней:

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

Другие советы

Код неверный. В итоге вы освободите imgView после его освобождения.

В вашем файле .m вы:

<Ол>
  • alloc it - > Вы владеете им
  • добавить его в качестве подпредставления - > вы и UIView владеет им
  • release it - > Вы не владеете им
  • Затем в dealloc вы выпускаете imgView, хотя, как мы установили на шаге 3 выше, он вам не принадлежит. Когда вы вызываете [super dealloc] , представление освободит все свои подпредставления, и я думаю, вы получите исключение.

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

    Код неверен, вы не должны выпускать его в методе init, просто когда вызывается dealloc (если вы хотите сохранить его как ivar, вам не нужно, если вам не нужен указатель на него в другом месте, так как addSubview: сохранит представление для вас).

    Я считаю, что причина, по которой он на самом деле не падает, заключается в том, что он все еще сохраняется суперклассом (от вызова addSubview :), поэтому, когда он выпущен в dealloc, он фактически сбалансирован. Представление, вероятно, удаляет себя из суперпредставления, когда оно сразу же после этого освобождается, поэтому, когда вызывается [super dealloc] , оно не перевыпускается. Это моя догадка, в аренду.

    Релиз в init неправильный.

    Вы упомянули "обычную практику" и безымянная книга. Я предлагаю взглянуть на канонические примеры от Apple: ViewTransitions - хороший пример для этого случая (и 2 вида для загрузки;)

    http://developer.apple.com/iphone/library /samplecode/ViewTransitions/index.html

    (у меня пока недостаточно репутации, чтобы добавить комментарий .)

    @bentford: поправьте меня, если я ошибаюсь, но я считаю, что для использования синтезированного установщика свойства imgView вы должны использовать " self.imgView ":

    self.imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]
    

    Если у вас нет self. , он просто использует ivar и не получает дополнительного удержания.

    Основной ответ таков: в примере кода должен быть только один [imgView release] ( после addSubview или в dealloc ). Однако я бы удалил [imgView release] из dealloc и оставил его после addSubview .

    На iPhone есть проблема; с помощью didReceiveMemoryWarning вы можете освободить объекты ( включая весь вид ) из-под вас. Если у вас есть набор сохранения для всего приложения, и вы не уважаете память, вы можете обнаружить, что приложение просто уничтожается.

    Хороший пример:
    если вы думаете о вложенном наборе из 3 представлений, View 1- > Вид 2- > Вид 3. Далее рассмотрим вызовы viewDidLoad и viewDidUnload . Если пользователь в настоящее время находится в «View 3», возможно, что View1 выгружен, и это то, где это становится неприятным.
     Если вы разместили объект внутри viewDidLoad и не освободили его после добавления его в подпредставление, тогда ваш объект не будет освобожден, когда view1 выгружен, но view1 все еще выгружен.
      viewDidLoad будет запущен снова, и ваш код будет запущен снова, но теперь у вас есть два экземпляра вашего объекта вместо одного; один объект будет находиться в нигде с ранее выгруженным видом, а новый объект будет для текущего видимого вида. Промойте, вспените и повторите, и вы обнаружите, что ваше приложение падает из-за утечек памяти.

    В этом примере, если данный блок кода является энергозависимым и имеет шанс на повторное выполнение ( из-за памяти или незагруженного представления ), я бы удалил [imgView release ]; из dealloc и оставьте его после addSubView.

    Вот ссылка на основные концепции сохранения / выпуска: http://www.otierney.net/objective-c.html#retain

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top