ios - Dealloc no es llamado en la aplicación ARC
ios5 automatic-ref-counting (7)
Tengo un UIViewController que se inserta en un controlador de contenedor y luego se apaga, y utilizando el instrumento de asignaciones, puedo ver que el controlador de vista se destruye después. Sin embargo, nunca se alcanza un punto de interrupción en el dealloc del controlador. ¿Alguien sabe por qué no se llama dealloc? ¿Es posible que ARC destruya un objeto sin llamar a dealloc?
Además, desactivé NSZombies (algunos han dicho que puede causar que dealloc no se active).
Editar:
Dealloc no hace mucho, solo imprime en la consola, y nunca se llama:
- (void)dealloc { NSLog(@"Deallocating..."); }
No puedo publicar el controlador de contenedor; es propietario y muy complicado. Dealloc se llama constantemente en algunos controladores y no en otros. Si puedo encontrar el tiempo, intentaré y publicaré una versión simplificada que reproduzca el problema.
¿Hay alguna manera de verificar que NSZombies está deshabilitado?
Edit2
Estoy publicando una captura de pantalla de los instrumentos; me parece que está desasignando correctamente.
¿Tienes NSZombieEnabled? Ver esta pregunta:
¿Por qué el objeto no está desasignado cuando se usa ARC + NSZombieEnabled?
Me quedé perplejo por esto por un tiempo yo mismo ...
Aquí hay otro consejo (me pasó a mí):
tl; dr: Mire también las variables de instancia de su clase, no solo las propiedades de la clase. ¿Estás asignando cualquier variable de instancia en el código y no estableciéndolo a nil
más adelante?
Tuve una clase con @property (nonatomic, strong)
propiedades ( @property (nonatomic, strong)
y @property (nonatomic, weak)
) en su archivo de encabezado. Comentaba esas propiedades una por una para ver si esto cambiaría algo. No lo hizo. La clase principal todavía no estaba siendo desasignada. Entonces el problema no estaba en las propiedades.
Lo que hice después fue mirar las variables de instancia. Tenía una variable de instancia (que era un UIViewController
), que creé en viewDidLoad
. ¡Este nunca fue desalojado!
Cuando eliminé esta variable, efectivamente, mi clase principal se llama dealloc.
Entonces, como este no fue desasignado, mi clase principal tampoco fue desasignada. Mover esa variable de instancia como propiedad resolvió el problema para mí.
Pregunta: No estoy seguro de por qué sucede esto. ¿El sistema operativo tiene un mejor control sobre las propiedades de una clase, que sobre las variables de instancia? Parece un poco raro que la clase padre que contiene la variable de instancia no se libere debido a su variable de instancia.
En mi caso, fue NSTimer
. Conserva su objetivo, por lo que debe invalidar el temporizador cuando haya terminado con el controlador de vista.
Incluso con ARC puede inspeccionar manualmente el recuento de referencias:
CFIndex rc = CFGetRetainCount((__bridge CFTypeRef)myObj);
Puede estar seguro si su código está colgado en un ciclo de memoria.
Me encontré con un problema similar. ¿Tienes algún bloque en el que te refieres a "sí mismo"? Tuve algunos bloqueos para la observación de notificaciones en mi inicio cuando me refería al ''yo''. En virtud de ARC self se conserva en bloques. Mi dealloc no recibía llamadas y ahí era donde estaba eliminando la observación.
El truco consiste en crear una referencia __weak (iOS 5+) o __unsafe_unretained (iOS 4.x) a su "auto" y usarla para acceder a uno mismo o a cualquier _iVars (esto hará que también se retenga a "self") en el bloquear. Aquí hay un ejemplo.
__unsafe_unretained TableViewController *weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
if (weakSelf.tableView) {
[weakSelf.tableView reloadData];
}
}];
Mi problema fueron los delegados.
¡Controle a sus delegados! La propiedad de delegado debe tener weak
especificación weak
:
weak var delegate: SomeProtocol?
o
@property (weak, nonatomic) id<SomeProtocol> delegate;
Si el VC no llama a dealloc, entonces apostaría a que hay una referencia circular en algún lugar de su código, lo que impide que ARC llame a dealloc.
Algunas cosas para verificar:
- ¿Tiene un objeto instanciado que haga referencia al VC?
- Si necesita hacer referencia al VC, asegúrese de haber utilizado el atributo ''__unsafe_unretained'' o ''weak'' (iOS5 +) para que el ciclo de retención no se produzca.
Fui mordido en el trasero cuando mis declaraciones de delegado no utilizaron __unsafe_unretained.