Pergunta

Aqui é uma prática comum que vejo frequentemente (incluindo de um livro muito popular desenvolvedor iPhone)

No arquivo .h:

@interface SomeViewController : UIViewController
{
  UIImageView *imgView;
}

Em algum lugar no arquivo .m:

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

E depois, vemos isso ...

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

} 

Desde imgView tem uma alocação de correspondência e de liberação, é a liberação de imgView em dealloc necessário?

Onde está a imgView retidos pela chamada addSubview contabilizada?

Foi útil?

Solução

Sim, esse código tem problemas. É libera o imgView muito cedo que poderia potencialmente causar acidentes em circunstâncias raras lojas de um objeto em uma variável de instância sem mantê-la, e é geralmente só vai sobre gerenciamento de memória de forma errada.

Uma maneira correta de fazer isso seria:

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

E na implementação;

@synthesize imgView;

Em algum lugar no módulo:

//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];

E o dealloc permanece o mesmo:

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

Outras dicas

O código é incorreta. Você vai acabar liberando imgView depois de ter sido desalocada.

Em seu arquivo .m, você:

  1. alloc-lo -> você possui it
  2. adicioná-lo como um subview -> você e o UIView é o dono
  3. release-lo -> você não possui-lo

Então, em dealloc, você release imgView embora, como estabelecido no passo 3 acima, você não ele próprio. Quando você chama [super dealloc], a visão vai lançar todos os seus subviews, e eu imagino que você vai receber uma exceção.

Se você quiser manter um ivar de imgView, sugiro não chamando release depois de adicioná-lo como um subview, e manter o seu dealloc o mesmo. Dessa forma, mesmo se imgView é em algum ponto removido da hierarquia de exibição, você ainda tem uma referência válida para ele.

O código é incorreto, você não deveria estar lançando-o no método init, justamente quando dealloc é chamado (Isto é, se você quiser mantê-lo como um ivar, você não precisa a menos que você precisa de um ponteiro para ele em outros lugares desde addSubview:. reterá a vista para você)

Acredito que a razão não é realmente falhando é porque ainda está sendo retida pela superclasse (a partir da chamada para addSubview :), então quando for lançado em dealloc que está realmente equilibrado. O ponto de vista, provavelmente, remove-se do superview quando é desalocada imediatamente depois, por isso, quando [super dealloc] é chamado não está sendo over-lançado. Esse é o meu palpite, pelo arrendamento.

Release em init está incorreto.

Você mencionou "prática comum" e um livro chamado-un. Sugiro olhar para os exemplos canônicos da Apple: ViewTransitions é um bom exemplo para este caso (e 2 vistas para inicialização;)

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

(Eu não tenho reputação suficiente para comentário add ainda.)

@bentford: me corrija se eu estiver errado, mas acredito que, a fim de usar setter sintetizado da propriedade imgView, você deve usar "self.imgView":

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

Se você não tem self. , é só usar o ivar, e ele não está recebendo reter o adicional.

A resposta básica é, deve haver apenas um [imgView release] no código de exemplo ( se é depois addSubview ou em dealloc ). No entanto, gostaria de remover [imgView release] de dealloc e deixá-lo após addSubview.

Há um prendedor no iPhone; com didReceiveMemoryWarning, você poderia ter objetos (, incluindo uma vista inteira ) lançado debaixo de você. Se você tiver uma aplicação em toda a reter set e você não respeitar a memória, então você pode encontrar o aplicativo simplesmente ser morto.

Um exemplo bom é:
se você pensar em um conjunto aninhado de 3 vistas, Ver 1-> Ver 2> View 3. Em seguida, considere o 'viewDidLoad' e chamadas dos viewDidUnload '. Se o usuário está atualmente em 'View 3', é possível que View1 é descarregado, e isso é onde fica desagradável.
Se você alocado um objeto dentro viewDidLoad e não liberá-lo depois de o adicionar à subexibição, então o seu objeto não é liberado quando view1 é descarregado, mas, view1 ainda é descarregado.
viewDidLoad será executado novamente e seu código será executado novamente, mas agora você tem duas instâncias de seu objeto em vez de um; um objeto estará em nowhereland com a visão previamente descarregados e o novo objeto será para a vista visível no momento. Rinse, espuma e repita e você encontrar a sua aplicação deixar de funcionar a partir de vazamentos de memória.

Neste exemplo, se o bloco de dados de código é volátil e tem uma chance de ser executado novamente ( se por causa de memória ou uma visão descarregada ), eu iria remover [imgView release]; de dealloc e deixá-lo após addSubview.

Aqui está um link em reter conceitos básicos / Lançamento: http://www.otierney.net/objective-c.html#retain

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top