2009-05-05 5 views
6

Вот обычная практика я вижу часто (в том числе от очень популярных разработчиков iPhone книги)Управление 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 имеет соответствующий набор и освобождение, является ли выпуск imgView в dealloc необходимым?

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

ответ

-1

Да, этот код имеет проблемы. Он выпускает 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]; 

И dealloc остается прежним:

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

imgView не выпущен слишком рано. Он сохраняется в addSubview. распространенная идиома для выпуска сразу после добавления через addSubview (или любые другие сохраняемые вызовы, такие как pushViewController UINavigationController. – Boon

+1

Немного более простой метод - назначить ivar (imgView) непосредственно вместо использования self.imgView позже. Это устраняет необходимость в [newImgView release] позже в коде. – Sophtware

+0

@boon К сожалению, вы совершенно правы - я думаю, что, должно быть, неправильно понял исходный код. Во всяком случае, сохранение чего-либо в переменной экземпляра после того, как вы его выпустили, является ошибкой, вы можете написать код, который отправляет сообщение объекту после его освобождения (хотя я признаю, что это очень маловероятно в этом конкретном случае). –

9

Код недействителен. Вы закончите выпуск imgView после того, как он будет освобожден.

В файле .m, вы:

  1. alloc это -> у вас есть это
  2. добавить его как подвид -> вы и the UIView owns it
  3. release это -> вы дон «т его владельцем

Тогда в dealloc, ты release imgView хотя, как мы установили на шаге 3 выше, вы не являетесь его владельцем. Когда вы вызываете [super dealloc], представление выдает все его подзоны, и я думаю, вы получите исключение.

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

0

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

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

0

Неверный выпуск в init.

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

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

0

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

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

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

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

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

+0

Тогда мне интересно, почему вы должны реализацию обозначают.. imgView в файле .h вообще? Я серьезно прошу, потому что я не понимаю. Если вы отпустите сразу после того, как вы закончите назначение свойства .image, почему бы не создать экземпляр imgView прямо перед его использованием? – Jann

+0

Вы для OP, это, вероятно, не нужно. Используется ли изображение в другом месте? Тогда, вероятно, это необходимо. – nessence

0

(Я не хватает репутации к добавить свой комментарий еще.)

@bentford: Исправьте меня, если я ошибаюсь, но я считаю, что в Чтобы использовать синтезированный сеттер свойства imgView, вы должны использовать «я».imgView ":

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

Если у вас нет самостоятельно, это просто с помощью Ивар, и он не получает дополнительный сохранить

+0

Я думаю, я был в замешательстве. Я удалил свой ответ, поскольку это не помогло. Спасибо за ответ. – bentford

Смежные вопросы