objective c - ViewController respondsToSelector: mensaje enviado a la instancia desasignada(CRASH)
objective-c ios (7)
Me encontré con el mismo problema en iOS ayer. He hecho IAP en la subvista "Acerca de" de la aplicación y agregué el Observador de transacciones 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 volver a comprar, ocurrió 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];
}
Ok, aquí está el trato, odio hacer preguntas sobre mi depuración y fallas. Porque generalmente los manejo yo mismo, pero no puedo hacerlo bien, incluso después de ver varias preguntas .
Bien, aquí está el problema, encuentro que mi aplicación se enciende y se apaga aleatoriamente con este rastro de pila:
*** -[ViewController respondsToSelector:]: message sent to deallocated instance 0x1e5d2ef0
Donde ViewController
puede variar, a veces el lugar donde mi código falla, NO tiene relevancia para ese ViewController
particular y no lo posee o no lo llama.
Además, para obtener esa traza en la consola, he habilitado Zombies, de lo contrario no recibiría ninguna impresión de consola, solo obtendría: objc_msgSend
, lo que sé es que estoy objc_msgSend
mensajes a algo que se ha publicado. Pero no puedo encontrar dónde está ... ¡Estoy realmente atascado! Normalmente siempre depuro mis fallas, así que estoy realmente atrapado en esto.
De nuevo, esto se bloquea en diferentes lugares en diferentes momentos, dentro y fuera. Y el lugar donde se bloquea casi no tiene relevancia para ViewController
. Y encuentro esto muy confuso.
¿Necesitas alguno de mi código? Tengo muchos archivos y dado que se está bloqueando en diferentes lugares, la distribución de mi código será un desastre.
He tratado de agregar puntos de ruptura simbólicos sin suerte, y Zombies no está disponible en la aplicación Instruments para iOS. No puedo ejecutar mi aplicación en el simulador ya que tiene marcos de arquitectura no compatibles.
Gracias a todos...
Para cualquiera que no pueda resolverlo, estas son algunas otras técnicas:
https://.com/a/12264647/539149
https://.com/a/5698635/539149
https://.com/a/9359792/539149
https://.com/a/15270549/539149
https://.com/a/12098735/539149
Puede ejecutar Instrumentos en Xcode 5 haciendo clic en el proyecto emergente-> Editar esquema ... Perfil -> Instrumento y elegir Asignaciones o Fugas, luego perfilar su aplicación, luego detener Instrumentos, hacer clic en el botón de información en Asignaciones y "Activar Detección NSZombie" .
Sin embargo, para los mensajes que provienen directamente de com.apple.main-thread, esto probablemente no revelará nada.
Me golpeé la cabeza con esto durante más de dos horas y la respuesta resultó ser un exceso de lanzamiento, que descubrí comentando 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 volver a establecer las llamadas a NULL libera, disminuyendo el refcount y liberando la memoria de inmediato hasta más adelante cuando las variables que hacen referencia a viewController hayan terminado con ella.
De modo que habilite ARC o asegúrese de que su proyecto use constantemente release o NULL, pero no ambos. Mi preferencia es usar NULL porque entonces no hay posibilidad de hacer referencia a un zombie, pero hace que encontrar donde los objetos se lanzan sea más difícil.
Tuve el mismo problema en OS X.
Para resolver esto no es suficiente - (void)dealloc
método como @SoftwareEvolved ya dijo. Pero desafortunadamente - (void)viewWillDisappear
está disponible solo en la versión 10.10 y posterior.
Introduje un método personalizado en mi subclase NSViewController donde establecí todas las referencias peligrosas a zombies en nil. En mi caso, eso era propiedades de NSTableView
( delegate
y 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.
Tuve el mismo problema. Fue difícil encontrar el problema de causa del delegado, porque no indica ninguna línea o enunciado del código. Así que lo he intentado de alguna manera. Tal vez sea útil para usted.
- Abra el archivo xib y desde el propietario del archivo, seleccione el menú "mostrar el inspector de conexiones" del lado derecho. Los delegados aparecen en la lista, configúrelos en cero y se sospecha de ellos.
- (Igual que mi caso) Property Object like 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; } }
Tuve un problema muy similar y me di cuenta de que se debía a la configuración de los delegados del controlador de navegación.
El 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;
}
}
Use los instrumentos para rastrear los errores de instancia desasignados. Perfila tu aplicación ( Cmd ⌘ + I ) y elige la plantilla Zombies . Después de que su aplicación se esté ejecutando, intente bloquearla. Deberías obtener algo como eso:
Haga clic en la flecha al lado de la dirección en el popover para mostrar el objeto que fue llamado después de que fue desasignado.
Debería ver ahora que cada llamada que ha cambiado conserva el recuento de este objeto. Esto podría deberse a que se envían mensajes directamente de retención / liberación, así como a que se agotan los grupos de liberación automática o se insertan en NSArrays.
La columna RefCt muestra retainCount después de invocar la acción y la persona que llama 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ó esto (si esto no funciona, puede examinar la llamada seleccionándola y eligiendo su contraparte en el panel Detalle ampliado ):
Esto le permitirá examinar todo el ciclo de vida de retención de objeto y probablemente encontrará su problema de inmediato. Todo lo que tienes que hacer es encontrar retener la última versión .
tuvo un problema similar En mi caso, un viewController necesitaba obtener eventos de navigationController, por lo que se estaba registrando como 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 el VC dejando la jerarquía de la vista justo antes de que realmente lo haga. Utiliza un método introducido en iOS 5 para determinar cuándo se está reproduciendo la vista y no empujando
-(void) viewWillDisappear:(BOOL) animated
{
[super viewWillDisappear:animated];
if ([self isMovingFromParentViewController])
{
if (self.navigationController.delegate == self)
{
self.navigationController.delegate = nil;
}
}
}
¡No más accidentes!