exemplo correto:
- (void)dealloc { [viewController release]; [window release]; [super dealloc]; }
exemplo errado:
- (void)dealloc { [super dealloc]; [viewController release]; [window release]; }
Embora em quase todos os outros casos, ao replace um método, eu primeiro chamaria a implementação do método do super, neste caso, apple sempre chama [super dealloc] no final. Por quê?
É apenas uma diretriz. Você pode ligar para outras instruções após [super dealloc]
. no entanto, você não pode mais acessar as variables da superclass porque elas são liberadas quando você chama [super dealloc]
. É sempre seguro chamar a superclass na última linha.
Também as chaves KVO e dependentes (acionadas) podem produzir efeitos colaterais, se dependerem de variables de membros já liberadas.
Eu não sei nada sobre programação para o iPhone, mas eu diria que é pela mesma razão que os destruidores precisam ser chamados na ordem inversa. Você quer ter certeza de que todo o seu ‘lixo’ está limpo antes de chamar sua superclass. Se você fizer o contrário, as coisas podem ficar confusas. Por exemplo, se o seu destruidor precisar acessar a memory que o super-destrutor já liberou:
class X { private Map foo; function __construct() { foo = new Map(); } function __destruct() { foo.free; } } class Y extends X { function __construct() { super.__construct(); map.put("foo", 42); } function __destruct() { super.__destruct(); if (map.containsKey("foo")) { // boooooooooom! doSomething(); } } }
Você não pode encontrar esse problema em seu código, porque “você sabe o que está fazendo”, mas é uma prática melhor e mais segura geral não fazer essas coisas.
[super dealloc] está liberando a memory usada pelo seu object, incluindo os pointers para viewController e window. Referir-se a variables depois de liberá-las é perigoso, na melhor das hipóteses.
Veja esta resposta .
Aqui está o exemplo real onde [super dealloc] deve ser o último, caso contrário, a chamada para removeFromRunLoop causará falha. Eu não tenho certeza do que acontece dentro de removeFromRunLoop do NSOutputStream, mas parece que ele acessa ‘self’ nesse caso.
Configuração:
[outputStream setDelegate:self]; [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
Dealloc:
- (void)dealloc { if (outputStream) { [outputStream close]; [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [outputStream release]; outputStream = nil; } delegate = nil; [super dealloc]; // must be last! }
Você praticamente tem quase [super dealloc]
no final porque libera as variables da superclass e elas não podem mais ser acessadas.
Uma exceção é se você tiver uma subclass de UITableViewController que esteja usando outra class como seu representante de exibição de tabela. Nesse caso, você deve liberar o delegado de exibição de tabela após [super dealloc]
porque a visualização de tabela está [super dealloc]
referência ao delegado de exibição de tabela e a exibição de tabela deve ser liberada primeiro.
[até o último post] O tableView referenciando o delegado não seria responsável por liberar seu próprio delegado? Eu acho que é mantido quando definido (para que você possa liberar ou autorelease) e ele iria cuidar de si mesmo?
Quanto à questão do OP, eu sempre chamarei o super primeiro se estou construindo e telefono para o último se estou destruindo. Eu penso nisso como “eu quero ter super construir o que ele quer para que eu possa construir sobre isso, e eu quero super derrubar por último depois de limpar depois de mim.” Praticamente todas as chamadas que eu uso estão sendo construídas, exceto o dealloc, então é por isso que você o veria por último no meu código dealloc sempre.