ViewController respondeToSelector: mensaje enviado a la instancia desasignada (CRASH)

95

Ok, aquí está el trato, odio hacer preguntas sobre mi depuración y fallas. Porque normalmente los manejo yo mismo, pero simplemente no puedo evitar esto, incluso después de ver varias preguntas .

Ok, aquí está el problema, encuentro que mi aplicación se bloquea y se bloquea aleatoriamente con este seguimiento de pila:

*** -[ViewController respondsToSelector:]: message sent to deallocated instance 0x1e5d2ef0

Donde ViewControllerpuede variar, a veces el lugar donde mi código falla, NO tiene relevancia para ese particular ViewControllery no lo posee ni lo llama.

Además, para obtener ese seguimiento de la consola, habilité Zombies, de lo contrario no obtendría ninguna impresión de la consola, solo obtendría:, objc_msgSendlo que sé que significa que estoy enviando un mensaje de algo que se publica. Pero no puedo encontrar dónde está ... ¡Estoy realmente atascado! Por lo general, siempre depuro mis bloqueos, por lo que estoy realmente atascado en esto.

Nuevamente, esto se bloquea en diferentes lugares en diferentes momentos, de forma intermitente. Y el lugar donde se estrella casi no tiene relevancia para el ViewController. Y encuentro esto muy confuso.

¿Necesitas algo de mi código? Tengo muchos archivos y, dado que se bloquea en diferentes lugares, ¡distribuir mi código será un desastre!

Intenté agregar puntos de interrupción simbólicos sin suerte, y Zombies no está disponible en la aplicación Instrumentos para iOS. No puedo ejecutar mi aplicación en el simulador ya que tiene marcos de arquitectura no compatibles.

Gracias a todos...

MCKapur
fuente
¿miró esta pregunta? stackoverflow.com/questions/1585688/…
self
Suponiendo que la forma en que realiza la transición a sus vistas es coherente, tal vez pueda mostrarnos un ejemplo o dos. Si está haciendo llamadas estándar push / presentViewController, debería estar bien, pero veo a mucha gente aquí haciendo cosas como asignar / iniciar un controlador de vista, pero luego no hacer un push / present, sino simplemente agregar el controlador ver como una subvista. Solo un ejemplo aleatorio. Pero no podemos diagnosticar esto sin algún código. Con suerte, algunos fragmentos nos ayudarán a descubrir qué está pasando, así que veamos.
Rob
¿Qué tal habilitar puntos de ruptura simbólicos? Intente agregar estos: wiki.zemingo.com/index.php?title=Symbolic_Breakpoints
Stavash
@RobertRyan Yo uso presentModalViewController, no lo agrego como una subvista
MCKapur
En mi caso, mi controlador de vista infantil contenía un webView, y el VC secundario era el delegado del scrollView de webView. Necesitaba eliminar manualmente la referencia de delegado durante dealloc / viewWillDisappear o me bloqueé. Espero que ayude a alguien.
Dermot

Respuestas:

169

Utilice Instrumentos para rastrear errores de instancia desasignada. Perfile tu aplicación ( Cmd ⌘+ I) y elige la plantilla Zombies . Una vez que su aplicación se esté ejecutando, intente bloquearla. Deberías conseguir algo como eso:

ingrese la descripción de la imagen aquí

Haga clic en la flecha junto a la dirección en la ventana emergente para mostrar el objeto al que se llamó después de que se desasignó.

ingrese la descripción de la imagen aquí

Debería ver ahora cada llamada que ha cambiado y retener el recuento de este objeto. Esto podría deberse al envío directo de mensajes de retención / liberación, así como al drenaje de los grupos de liberación automática o la inserción en NSArrays.

La columna RefCt muestra retenerCount después de que se invocó la acción y el llamador responsable muestra el nombre de la clase y el método en el que se realizó. Cuando hace doble clic en cualquier retención / liberación, los instrumentos le mostrarán la línea de código donde se realizó (si esto no funciona, puede examinar la llamada seleccionándola y eligiendo su contraparte en el panel de detalles extendidos ):

ingrese la descripción de la imagen aquí

Esto le permitirá examinar todo el ciclo de vida del objeto de retenciónCount y probablemente encontrará su problema de inmediato. Todo lo que tienes que hacer es encontrar el retenido que falta para la última versión .

Johnny quien
fuente
3
Es posible que el problema no sea el último release, específicamente. El problema es que cualquier desequilibrio release. También puedo simplemente ser una falla en retainalgo a lo que estás manteniendo un puntero y haciendo referencia más tarde.
Ken Thomases
1
Además, no tengo una plantilla de instrumentos Zombie, eso puede deberse a que estoy usando Xcode Beta 4.5, mientras tanto
cambiaré
2
Oh, los zombis solo se proporcionan en el simulador de iOS. NO PUEDO ejecutar en el simulador de iOS, algunos de mis marcos y bibliotecas utilizados no son compatibles con la arquitectura
MCKapur
Solo una pequeña nota. Esto es de las novedades de xcode 5. "La plantilla del instrumento Zombies se ha mejorado en Xcode 5 y ahora admite su uso en dispositivos. El uso de Zombies en dispositivos requiere iOS 7". Esta nota te trajo a ti y 2 horas de mi precioso tiempo ...
nickfox
2
¿Qué significa si nuestra aplicación deja de fallar y deja de dar un error de "mensaje enviado a instancia desasignada" cuando conectamos este instrumento a ella? (Es como si la "enfermedad" desapareciera cuando el paciente recibe una "prueba de diagnóstico".)
Praxiteles
59

tenía un problema similar. En mi caso, un viewController necesitaba obtener eventos de navigationController, por lo que se estaba registrando como el delegado del controlador de navegación:

 self.navigationController.delegate = self;

El bloqueo ocurre cuando ese controlador fue desasignado pero aún era el delegado del controlador de vista. Agregar este código en dealloc no tuvo ningún efecto:

-(void) dealloc
{
    if (self.navigationController.delegate == self)
    {
        self.navigationController.delegate = nil;
    }

porque en el momento en que se llama a dealloc, el controlador de vista ya se ha eliminado de la jerarquía de vistas, por lo que self.navigationController es nulo, por lo que se garantiza que la comparación fallará. :-(

La solución fue agregar este código para detectar que el VC abandona la jerarquía de vista justo antes de que lo haga. Utiliza un método introducido en iOS 5 para determinar cuándo la vista se abre y no se empuja

-(void) viewWillDisappear:(BOOL) animated
{  
   [super viewWillDisappear:animated];
   if ([self isMovingFromParentViewController])
   {
      if (self.navigationController.delegate == self)
      {
           self.navigationController.delegate = nil;
      }
   }
}

¡No más choques!

software evolucionado
fuente
Yo también gracias. Solo se necesitan 4 horas de búsqueda para encontrar esta publicación.
daidai
Gracias por publicar, tuve el mismo problema ^^
Tyron
¿Cómo encuentran ustedes soluciones a problemas tan irritantes? Felicitaciones !!
ViruMax
4

Para cualquiera que no pueda resolverlo, aquí hay algunas otras técnicas:

https://stackoverflow.com/a/12264647/539149

https://stackoverflow.com/a/5698635/539149

https://stackoverflow.com/a/9359792/539149

https://stackoverflow.com/a/15270549/539149

https://stackoverflow.com/a/12098735/539149

Puede ejecutar Instrumentos en Xcode 5 haciendo clic en la ventana emergente del proyecto-> Editar esquema ... Perfil -> Instrumento y elija Asignaciones o Fugas, luego perfile su aplicación, luego detenga Instrumentos, haga clic en el botón de información en Asignaciones y "Habilitar Detección NSZombie" .

Sin embargo, para los mensajes que provienen directamente del subproceso com.apple.main, esto probablemente no revelará nada.

Me golpeé la cabeza con esto durante más de dos horas y la respuesta resultó ser un lanzamiento excesivo, que descubrí al comentar una copia de mi proyecto por fuerza bruta hasta que encontré al culpable:

[viewController release];
viewController = NULL;

El problema es que la versión no establece la variable en NULL.

Eso significa que al establecerlo en NULL, las llamadas se liberan nuevamente, disminuyendo el recuento de referencias y liberando la memoria inmediatamente hasta más tarde, cuando las variables que hacen referencia a viewController terminen con él.

Por lo tanto, habilite ARC o asegúrese de que su proyecto use consistentemente release o NULL pero no ambos. Mi preferencia es usar NULL porque entonces no hay posibilidad de hacer referencia a un zombi, pero hace que sea más difícil encontrar dónde se liberan los objetos.

Zack Morris
fuente
4

Ayer me encontré con el mismo problema en iOS. He creado IAP en la subvista "Acerca de" de la aplicación, y he agregado Transaction Observer en "Acerca de" viewDidLoad. Cuando compro por primera vez, no hay problema, pero después de volver a la ventana principal e ingresar sobre la subvista para comprar nuevamente, se produjo el problema "mensaje enviado a la instancia desasignada" y la aplicación se bloqueó.

- (void)viewDidLoad
{
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];                                           object:nil];
}

Después de eliminar Transaction Observer en dealloc, el problema está resuelto.

- (void)dealloc
{
    // Even though we are using ARC, we still need to manually stop observing any
    // NSNotificationCenter notifications.  Otherwise we could get "zombie" crashes when
    // NSNotificationCenter tries to notify us after our -dealloc finished.

    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
Ouyang Yong
fuente
Se arregló mi falla en tiempo de ejecución ... Estaba obteniendo un zombieobjeto para compras dentro de la aplicación. Después de muchas horas de excavación encontré este ... MUCHAS GRACIAS Hombre.
Mahendra
4

Tuve un problema muy similar y descubrí que se debía a que los delegados del controlador de navegación estaban configurados.

Lo siguiente resolvió mi problema,

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if (self.navigationController.delegate != self) {
        self.navigationController.delegate = self;
    }
}

-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    if (self.navigationController.delegate == self) {
        self.navigationController.delegate = nil;
    }
}
thatzprem
fuente
¡¡Gracias!! fue el mismo problema aquí.
pegpeg
2

Tuve el mismo problema en OS X.

Para resolver este - (void)deallocmétodo no es suficiente como ya dijo @SoftwareEvolved. Pero, lamentablemente, - (void)viewWillDisappearsolo está disponible en la versión 10.10 y posteriores.

Introduje un método personalizado en mi subclase NSViewController donde establecí todas las referencias peligrosas para zombis en nulo. En mi caso fueron NSTableViewpropiedades ( delegatey dataSource).

- (void)shutdown
{
  self.tableView.delegate = nil;
  self.tableView.dataSource = nil;
}

Eso es todo. Cada vez que estoy a punto de eliminar la vista de la supervista, necesito llamar a este método.

Astoria
fuente
2

Tuve el mismo problema. Fue difícil encontrar qué delegado causa el problema, porque no indica ninguna línea o declaración de código, así que lo intenté de alguna manera, tal vez sea útil para usted.

  1. Abra el archivo xib y, desde el propietario del archivo, seleccione "mostrar el inspector de conexiones" en el menú del lado derecho. Se enumeran los delegados, ajústelos a cero si se sospecha.
  2. (Igual que en mi caso) El objeto de propiedad como Textfield puede crear un problema, así que configure sus delegados en nil.
-(void) viewWillDisappear:(BOOL) animated{

[super viewWillDisappear:animated];

if ([self isMovingFromParentViewController]){

self.countryTextField.delegate = nil;

self.stateTextField.delegate = nil;

}

}
nadim
fuente