Quando devo liberar objetos em - (void) viewDidUnload em vez de em -dealloc?

103

Para que serve -(void)viewDidUnload?

Eu não poderia simplesmente relançar tudo -dealloc? Se a vista fosse descarregada, não -deallocseria chamada de qualquer maneira?

obrigado
fonte

Respostas:

51

Além do que já foi indicado, queria elaborar mais sobre a lógica por trás -viewDidUnload.

Uma das razões mais importantes para implementá-lo é que as UIViewControllersubclasses geralmente também contêm referências de propriedade a várias subvisualizações na hierarquia de visões. Essas propriedades podem ter sido definidas IBOutletsdurante o carregamento de uma ponta, ou programaticamente dentro -loadView, por exemplo.

A propriedade adicional de subvisualizações UIViewControllersignifica que mesmo quando sua visão é removida da hierarquia de visão e liberada para economizar memória, através da qual as subvisualizações também são liberadas pela visão, elas não serão realmente desalocadas porque o UIViewControllerpróprio ainda contém seus próprios itens pendentes retendo referências a esses objetos também. Liberar a UIViewControllerpropriedade adicional desses objetos garante que eles também serão desalocados para liberar memória.

Os objetos que você libera aqui são geralmente recriados e configurados novamente quando a UIViewControllervisualização é re-loaded, de um Nib ou por meio de uma implementação de -loadView.

Observe também que a UIViewController viewpropriedade está nilno momento em que este método é chamado.

Sean Patrick Murphy
fonte
1
Você deve ler developer.apple.com/library/ios/#featuredarticles/… para entender o ciclo de vida do controlador de visualização / visualização
Paul Solt
21

Como diz a documentação :

É chamado durante condições de pouca memória, quando o controlador de visualização precisa liberar sua visualização e quaisquer objetos associados a essa visualização para liberar memória.

Na mesma situação nãodealloc é chamado. Este método está disponível apenas no OS3 e superior. Lidar com a mesma situação no iPhone OS 2.x foi uma verdadeira dor!

Atualização de julho de 2015 : deve-se observar que viewDidUnloadfoi descontinuado no iOS 6 porque "as visualizações não são mais eliminadas em condições de pouca memória e, portanto, este método nunca é chamado." Portanto, o conselho moderno é não se preocupar com isso e usar dealloc.

Stephen Darlington
fonte
6
Também da documentação: "Você deve fazer isso apenas para objetos que podem ser facilmente recriados posteriormente, seja no método viewDidLoad ou em outras partes do seu aplicativo. Você não deve usar este método para liberar dados do usuário ou qualquer outra informação que não possa ser facilmente recriada ". Essa é uma pergunta que eu também fiz, obrigado!
leolobato
E se a visualização estiver visível no momento? Não seria ruim descartá-lo por causa de um aviso de pouca memória? ;) então o aplicativo ficaria em branco e vazio. Eu não entendo o ponto de liberar a visão por causa da pouca memória. Se eu não tiver uma visualização, sempre solto o controlador inteiro. Althogh, eu tenho um controlador de visualização raiz que permanece intacto e gerencia todo o carregamento / descarregamento de seus controladores de visualização filho ...
Obrigado
Não, você não usaria isso se apenas trocasse uma visualização por outra. Pense no caso em que você tem uma "pilha" de visualizações com um UINavigationController. Apenas uma visualização é visível e, se você tiver um aviso de memória, pode liberar todas as que não estão visíveis.
Stephen Darlington
Como você controla se viewDidUnload não é chamado na visualização visível atual, como Thanks notou?
arielcamus
1
viewDidUnload não será chamado na visualização visível no momento, apenas em visualizações que não são visíveis.
programa de
9

Isso ocorre porque você normalmente definirá o @propertycomo "(nonatomic, retain)"e como tal, o configurador que é criado para você libera o objeto atual e, em seguida, retém o argumento, ou seja

self.property = nil;

... faz algo ao longo das linhas de:

[property release];
property = [nil retain];

Portanto, você está matando dois coelhos com uma cajadada só: gerenciamento de memória (liberando o objeto existente) e atribuindo o ponteiro a nil (já que enviar qualquer mensagem a um ponteiro nulo retornará nulo).

Espero que ajude.

gazzaaa87
fonte
8

Lembre-se de que viewDidUnloadé um método no controlador de visualização, não na visualização. O método da visão dealloc será chamado quando a visão descarregar, mas o controlador da visão dealloc método não pode ser chamado até mais tarde.

Se você receber um aviso de pouca memória e sua visualização não estiver aparecendo, o que acontecerá, por exemplo, sempre que você usar um UIImagePickerController para permitir que o usuário tire uma foto, sua visualização será descarregada e precisará ser recarregada depois disso.

David Maymudes
fonte
isso faz sentido. O que acontece se eu sempre derrubar todo o controlador de exibição? Isso é o que eu realmente faço. Nesse caso, não preciso lidar muito com -viewDidUnload, certo? Eu nunca tive a situação de deixar cair apenas a vista, já que sempre deixo cair o controle inteiro se não estiver visível de qualquer maneira.
Obrigado
bem, lembre-se de que, no caso em que sua visualização está sendo exibida, mas você tem uma visualização em tela cheia como o ImagePicker em cima dela, sua visualização pode ser descarregada mesmo que você não planejasse que isso acontecesse.
David Maymudes
6

Conclusão:

Controladores de visualização têm uma propriedade de visualização. Normalmente, uma ponta ou pedaço de código adiciona outras visualizações a esta visualização. Isso acontece frequentemente dentro de um método -viewDidLoad, como este:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self createManyViewsAndAddThemToSelfDotView];
}

além disso, um arquivo nib pode criar um botão e anexá-lo à visualização do controlador de visualização.

No iPhone OS 2.2, quando -didReceiveMemoryWarning era invocado no sistema, era necessário liberar algo para liberar memória. Você poderia liberar toda a visão do controlador de visualização se isso fizesse sentido. Ou apenas conteúdos que consomem muita memória.

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

Agora, no novo OS 3.0, há um método -viewDidUnload, que será chamado do sistema quando a visualização for descarregada devido à falta de memória (corrija-me: quando exatamente isso é chamado?)

-viewDidUnload é usado para liberar todos os objetos que pertenciam ao próprio controlador de visualização e à visualização. O motivo: se um controlador de visualização contém referências a filhos da visualização, ou seja, um botão, as visualizações filho referenciadas não serão liberadas, porque sua contagem de retenção é> = 1. Depois de serem liberadas em -viewDidUnload, elas podem ser liberadas da memória.

obrigado
fonte
1
o lembrete em vista descarregou para fazer self.button = nil ;, não [botão de liberação] ;.
mk12 de
6

O viewWillUnload obsoleto da Apple, agora você deve usar didReceiveMemoryWarning ou dealloc para liberar seus objetos.

No iOS 6, os métodos viewWillUnload e viewDidUnload de UIViewController foram descontinuados. Se você estava usando esses métodos para liberar dados, use o método didReceiveMemoryWarning. Você também pode usar este método para liberar referências à visão do controlador de visualização, se não estiver sendo usada. Você precisaria testar se a visualização não está em uma janela antes de fazer isso.

Guilherme Torres Castro
fonte
5

Se o controlador de visualização for retirado da pilha do controlador de navegação e não for retido em nenhum outro lugar, ele será desalocado e desalocado será chamado em vez de viewDidUnload. Você deve liberar as visualizações criadas em loadView em dealloc, mas não é necessário definir as variáveis ​​como nulo, porque logo após o dealloc ser chamado, as variáveis ​​não existirão mais.

Colin
fonte
3

Você pode liberar qualquer subvisualização que você mantenha, por exemplo, aquele UIImageView que você reteve em seu método loadView, ou melhor ainda, a imagem que estava naquele UIImageView.

drvdijk
fonte