No Cocoa, preciso impedir que um objeto receba notificações KVO ao desalocá-lo?

StackOverflow https://stackoverflow.com/questions/13927

  •  08-06-2019
  •  | 
  •  

Pergunta

Quando eu registrei um objeto foo para receber notificações KVO de outro objeto bar (usando addObserver:...), se eu então desalocar foo preciso enviar um removeObserver:forKeyPath: mensagem para bar em -dealloc?

Foi útil?

Solução

Você precisa usar -removeObserver:forKeyPath: remover o observador antes -[NSObject dealloc] corre, então sim, fazendo isso no -dealloc método da sua classe funcionaria.

Melhor do que isso seria ter um ponto determinístico onde o dono do objeto que está fazendo a observação poderia dizer que está feito e será (eventualmente) desalocado.Dessa forma, você pode parar de observar imediatamente quando o objeto que está observando não for mais necessário, independentemente de quando ele for realmente desalocado.

É importante ter isso em mente porque o tempo de vida dos objetos no Cocoa não é tão determinístico quanto algumas pessoas parecem pensar.As diversas estruturas do Mac OS X vai envie seus objetos -retain e -autorelease, estendendo sua vida útil além do que você poderia imaginar que seria.

Além disso, ao fazer a transição para a coleta de lixo do Objective-C, você descobrirá que -finalize será executado em momentos muito diferentes - e em contextos muito diferentes - do que -dealloc fez.Por um lado, a finalização ocorre em um thread diferente, então você realmente não pode enviar com segurança -removeObserver:forKeyPath: para outro objeto em um -finalize método.

Atenha-se ao gerenciamento de memória (e outros recursos escassos) em -dealloc e -finalize, e use um separado -invalidate método para fazer com que um proprietário diga a um objeto que você terminou com ele em um ponto determinístico;faça coisas como remover observações KVO lá.A intenção do seu código ficará mais clara e você terá menos bugs sutis para resolver.

Outras dicas

Um pouco de informação extra que ganhei com uma experiência dolorosa:embora o NSNotificationCenter use zerar referências fracas ao executar na coleta de lixo, o KVO não o faz.Assim, você pode não remover um observador NSNotificationCenter ao usar o GC (ao usar reter/liberar, você ainda precisa remover seu observador), mas ainda deve remover seus observadores KVO, como Chris descreve.

Definitivamente concordo com Chris no comentário "Atenha-se ao gerenciamento de memória (e outros recursos escassos) em -dealloc e -finalize...".Muitas vezes vejo pessoas tentando invalidar objetos NSTimer em suas funções dealloc.O problema é que o NSTimer mantém seus alvos.Portanto, se o alvo desse NSTimer for self, dealloc nunca será chamado, resultando em vazamentos de memória potencialmente desagradáveis.

Invalidar em -invalidate e faça outra limpeza de memória em seu dealloc e finalize.

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