Dealloc personalizado y ARC (Objective-C)

208

En mi pequeña aplicación de iPad tengo una función de "cambio de idioma" que utiliza un observador. Cada controlador de vista se registra con mi observador durante su viewDidLoad:.

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

Cuando el usuario presiona el botón "cambiar idioma", el nuevo idioma se almacena en mi modelo y se notifica al observador y llama a un updateUi:selector en sus objetos registrados.

Esto funciona muy bien, excepto cuando tengo controladores de vista en un TabBarController. Esto se debe a que cuando se carga la barra de pestañas, obtiene los íconos de pestañas de sus controladores secundarios sin inicializar las vistas, por viewDidLoad:lo que no se llama, por lo que esos controladores de vista no reciben notificaciones de cambio de idioma. Debido a esto, moví mis registerObject:llamadas al initmétodo.

Cuando solía viewDidLoad:registrarme con mi observador, solía viewDidUnload:anular el registro. Como ahora me estoy registrando init, tiene mucho sentido anular el registro dealloc.

Pero éste es mi problema. Cuando yo escribo:

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

Me sale este error:

ARC prohíbe el envío explícito de mensajes de 'dealloc'

Como necesito llamar [super dealloc]para asegurar que las superclases se limpien correctamente, pero ARC lo prohíbe, ahora estoy atascado. ¿Hay otra manera de informarme cuando mi objeto está muriendo?

Niku
fuente
Como nota al margen, una situación como esta puede causar una pérdida de memoria, que no se mostraría en la herramienta Fugas. Si dataModel retiene la referencia al observador (que es lo predeterminado en ARC, incluso para ivars), nunca se llamará al dealloc, ya que el recuento de retención será mayor que cero. Por lo tanto, es posible que tenga que cancelar manualmente el registro del observador para permitir que se llame a dealloc en primer lugar.
Błażej Czapp
Implementé algo similar para las opciones para diestros y zurdos. El único VC que necesita el mensaje es el que se muestra actualmente. Otros miran el modelo en viewDidLoad o viewDidAppear para realizar cambios en la interfaz. Tal vez algo como esto funcionaría mejor.
Doug Watkins
@BlazejCzapp ya que está usando un UITabBarController, y digamos que el UITabBarController siempre tendrá una referencia al controlador registrado (como supongo que es el caso con sus controladores 'secundarios'), ¿seguirá siendo un problema la pérdida de memoria? No veo cuándo se asignará el controlador registrado. Gracias
Objectif

Respuestas:

419

Cuando usa ARC, simplemente no llama [super dealloc]explícitamente: el compilador lo maneja por usted (como se describe en el documento Clang LLVM ARC, capítulo 7.1.2 ):

- (void) dealloc
{
    [observer unregisterObject:self];
    // [super dealloc]; //(provided by the compiler)
}
justin
fuente
44
Si la vista tiene una referencia al observador, y el observador tiene una referencia a la vista, entonces tenemos una referencia circular. Por lo tanto, el recuento de referencia de la vista es mayor que 0 y deallocnunca se llama. ¿Tiene sentido llamar [observer unregisterObject:self]a Dealloc? ¿Qué me estoy perdiendo?
user443854
Eso quiere trabajar. porque el observador en sí tiene una referencia al controlador. eso evitará el acuerdo de ser llamado en primer lugar
hasan