2012-02-09 12 views
35

Tengo un UIViewController que se coloca en un controlador de contenedor y luego se apaga, y con 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?Dealloc no se llama en la aplicación ARC

Además, desactivé NSZombies (algunos han dicho que puede causar que dealloc no se active).

Editar:

dealloc no hace mucho, sólo imprime en la consola, y que nunca se llama:

- (void)dealloc { NSLog(@"Deallocating..."); }

no puedo publicar el controlador-contenedor que es propietario y demasiado 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 forma de verificar que NSZombies está deshabilitado?

Edit2

les dejo una captura de pantalla de los instrumentos; me parece que está desasignando correctamente.

enter image description here

+1

Se debería estar recibiendo llamados, incluso bajo ARC. Sin embargo, no puede incluir [super dealloc], ARC agregará eso para usted. Tal vez compartir el código para esta clase? – picciano

+0

¿Hay algún método en el método dealloc? – zaph

+1

Debe publicar el código '- (void) dealloc {}'. – NJones

Respuesta

19

Si dealloc no está siendo llamado por el VC, entonces yo apuesto a que es una referencia circular en algún lugar de su código, que está impidiendo ARC de llamar dealloc.

Algunas cosas a comprobar:

  1. ¿Tiene un objeto instanciado que las referencias de nuevo a la VC?
  2. Si necesita hacer referencia al VC, asegúrese de haber utilizado el atributo '__unsafe_unretained' o 'débil' (iOS5 +) para que el ciclo de retención no ocurra.

Fui mordido en el trasero cuando mis declaraciones de delegado no utilizaron __unsafe_unretained.

88

simplemente 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 'self' se retenga como bien) en el bloque. 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]; 
     } 
    }]; 
+0

Después de revisar gran cantidad de código migrado (desde proyectos que no son de arco hasta proyectos de arco), puedo confirmar que esta es una fuente importante de retención no deseada -cycles. Al final: un bloque es útil y se crea fácilmente, ¡verdad! – leviathan

+0

Al no anular el registro del observador, eso significa que se disparará en respuesta a la notificación * para siempre *, incluso después de que 'self' haya desaparecido. Y si agrega este observador varias veces, cada vez que se produzca esta notificación, disparará múltiples observadores inútiles, para siempre. Esta no puede ser una buena práctica de programación. – user102008

+7

Para simplificar, podemos usar '__weak typeof (self) weakSelf = self;' – Vive

16

Incluso con ARC se puede inspeccionar manualmente la cuenta de referencia:

CFIndex rc = CFGetRetainCount((__bridge CFTypeRef)myObj); 

Usted puede saber con certeza si su código se cuelga en un ciclo de memoria.

+0

Estoy de acuerdo con @Dean Liu: sin perjuicio de los instrumentos, sospecho que no se está desasignando debido a un ciclo de memoria. De vez en cuando me engancho con ciclos usando Bloques, especialmente si el bloque se refiere a 'uno mismo', es muy fácil de hacer. – jbbenni

+0

¡gracias eso es muy útil! –

+3

¡Esto ayudó! (Seguramente sería bueno si hubiera un método de llamada de función correspondiente que proporcionara una lista de todos los objetos que hacían referencia a un objeto). –

9

Aquí está otra extremidad (me pasó a mí):

tl; dr: Mire sus variables de instancia de clase, así, no sólo las propiedades de la clase. ¿Está asignando una variable de instancia en el código y no configurándola en nil más tarde?

Tenía una clase con un grupo de 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 vistazo a las variables de instancia. Tenía una variable de instancia (que era UIViewController), que creé en viewDidLoad. ¡Este nunca consiguió desasistido!

Cuando quité esta variable, por supuesto, mi clase principal llamado dealloc.

Así pues ésta no se dealloc-ed, mi clase principal no era dealloc-ed tampoco. 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.

21

En mi caso fue NSTimer. Conserva su objetivo, por lo que debe invalidar el temporizador cuando haya terminado con el controlador de vista.

13

Mi problema era delegados.

Compruebe sus delegados! La propiedad debe tener delegado weak especifica:

@property (weak, nonatomic) id<SomeProtocol> delegate;

Cuestiones relacionadas