Dealloc personalizado e ARC (Objective-C)

208

No meu pequeno aplicativo para iPad, tenho uma função "mudar idioma" que usa um observador. Todo controlador de exibição se registra no meu observador durante o processo viewDidLoad:.

- (void)viewDidLoad
{
    [super viewDidLoad];
    [observer registerObject:self];
}

Quando o usuário pressiona o botão "alterar idioma", o novo idioma é armazenado no meu modelo e o observador é notificado e chama um updateUi:seletor em seus objetos registrados.

Isso funciona muito bem, exceto quando tenho controladores de exibição em um TabBarController. Isso ocorre porque, quando a barra de guias é carregada, ela busca os ícones de guias de seus controladores filhos sem inicializar as visualizações, por isso viewDidLoad:não é chamada, portanto esses controladores de exibição não recebem notificações de alteração de idioma. Por isso, mudei minhas registerObject:chamadas para o initmétodo

Quando eu costumava viewDidLoad:me registrar com meu observador, costumava viewDidUnload:cancelar o registro. Como agora estou me registrando init, faz muito sentido cancelar o registro dealloc.

Mas aqui está meu problema. Quando escrevo:

- (void) dealloc
{
    [observer unregisterObject:self];
    [super dealloc];
}

Eu recebo este erro:

O ARC proíbe o envio explícito de mensagens de 'dealloc'

Como preciso ligar [super dealloc]para garantir que as superclasses limpem corretamente, mas o ARC proíbe isso, agora estou preso. Existe outra maneira de me informar quando meu objeto está morrendo?

Niku
fonte
Como observação lateral - situações como essa podem causar vazamento de memória, o que não seria exibido na ferramenta Vazamentos. Se o dataModel reter a referência ao observador (que é a coisa padrão no ARC, mesmo para ivars), o acordo desagradável nunca será chamado, pois a contagem de retenção será maior que zero. Portanto, talvez seja necessário cancelar o registro manual do observador para permitir que o acordo seja chamado em primeiro lugar.
Błażej Czapp
Eu implementei algo semelhante para opções de destros e canhotos. O único VC que precisa da mensagem é o atualmente exibido. Outros observam o modelo em viewDidLoad ou viewDidAppear para fazer alterações na interface. Talvez algo assim funcionasse melhor.
Doug Watkins
@BlazejCzapp, pois ele está usando um UITabBarController, e digamos que o UITabBarController sempre terá uma referência ao controlador registrado (como eu acho que é o caso de seus controladores 'filhos'), o vazamento de memória ainda será um problema? Não vejo quando o controlador registrado será alocado. Obrigado
Objectif 28/10

Respostas:

419

Ao usar o ARC, você simplesmente não chama [super dealloc]explicitamente - o compilador lida com você (como descrito no documento Clang LLVM ARC, capítulo 7.1.2 ):

- (void) dealloc
{
    [observer unregisterObject:self];
    // [super dealloc]; //(provided by the compiler)
}
justin
fonte
4
Se a visão mantém uma referência ao observador, e o observador mantém uma referência à visão, então temos uma referência circular. Portanto, a contagem de referência da exibição é maior que 0 e deallocnunca é chamada. Faz sentido chamar [observer unregisterObject:self]desalocação? o que estou perdendo?
user443854
isso quer trabalhar. porque o próprio observador mantém uma referência ao controlador. que a vontade impedindo a dealloc de ser chamado em primeiro lugar
Hasan