iphone - deeplinking - ios deeplink
UINavigationController setViewControllers hace que se cuelgue la aplicaciĆ³n (3)
Creo que valdría la pena ejecutarlo a través de Instrumentos en el modo Zombies. Esto es casi seguro un problema de memoria, con algo accediendo a un objeto que ya se ha lanzado.
Tengo un problema extraño y no sé si es mi error (muy probablemente) o un error en UINavigationController.
Uso UINavigationController en mi aplicación. En algunos casos, necesito navegaciones complicadas como "pantallas de pop 2 y push new". Actualmente lo hago obteniendo el navigationController.viewControllers
actual, modificando la colección y llamando [navigationController setViewControllers:newStack animated:YES]
.
Ocurre que esto hace que mi aplicación se cuelgue muy a menudo. Por lo general, los bloqueos son SIGBUS o SIGSEGV. Los pasos para reproducirse son los siguientes:
- Haz una de esas complicadas navegaciones
- Navega hacia atrás una o dos veces dependiendo del tipo de navegación
- ¡Choque!
Las cosas interesantes son eso:
- Si la navegación era simplemente "varias pantallas atrás", la próxima parte posterior se bloqueará. Si la navegación fuera "varias pantallas atrás y presione la nueva pantalla", la segunda vuelta se bloqueará. Además, en tales casos, las navegaciones como atrás, adelante, atrás, atrás usualmente no bloquean la aplicación
- Lo más extraño: si lo hago
[navigationController popToRootViewControllerAnimated:NO]
antes de actualizar la pila, la aplicación no falla o al menos falla mucho más (no pude reproducir el bloqueo).
Ejemplo de rastreo de la pila de choque capturado por mi controlador de señal:
- 0x0027a9 mysighandler ()
- 0x3293d82b _sigtramp ()
- 0x31c59065 - [UIAplication sendAction: to: from: forEvent:]
- 0x31c59005 - [UIAplication sendAction: toTarget: fromSender: forEvent:]
- 0x31c58fd7 - [UIControl sendAction: to: forEvent:]
- 0x31c58d31 - [UIControl _sendActionsForEvents: withEvent:]
- 0x31c59645 - [UIControl touchesEnded: withEvent:]
- 0x31c5865d - [UIWindow _sendTouchesForEvent:]
- 0x31c58039 - [UIWindow sendEvent:]
- 0x31c5492f - [UIApplication sendEvent:]
- 0x31c543a7 _UIApplicationHandleEvent ()
- 0x3352c9ed PurpleEventCallback ()
- 0x3358ac2d CFRunLoopRunSpecific ()
- 0x3358a35d CFRunLoopRunInMode ()
- 0x3352bb33 GSEventRunModal ()
- 0x3352bbdf GSEventRun ()
- 0x31c1976f - [UIAplicación _run]
- 0x31c18473 UIApplicationMain ()
- 0x00214d main ()
- 0x0020c4 start ()
Otro:
- 0x002945 mysighandler ()
- 0x3293d82b _sigtramp ()
- 0x31c5ead3 - [UIScrollView _updatePanWithStartDelta: event: gesture: ignorandoDirectionalScroll:]
- 0x31c5e435 - [UIScrollView handlePan:]
- 0x31d14651 - [UITableView handlePan:]
- 0x33590da7 - [Protocol performSelector: withObject:]
- 0x31c428b5 - [UIGestureRecognizer _updateGestureWithEvent:]
- 0x31c427a9 - [UIGestureRecognizer _updateGestureStateWithEvent: afterDelay:]
- 0x31c583d5 - [UIWindow _sendGesturesForEvent:]
- 0x31c5802b - [UIWindow sendEvent:]
- 0x31c5492f - [UIApplication sendEvent:]
- 0x31c543a7 _UIApplicationHandleEvent ()
- 0x3352c9ed PurpleEventCallback ()
- 0x3358ac2d CFRunLoopRunSpecific ()
- 0x3358a35d CFRunLoopRunInMode ()
- 0x3352bb33 GSEventRunModal ()
- 0x3352bbdf GSEventRun ()
- 0x31c1976f - [UIAplicación _run]
- 0x31c18473 UIApplicationMain ()
- 0x0022e9 principal ()
- 0x002260 start ()
Ejemplo de implementación de navegación "complicada":
@implementation UINavigationController(MyCategory)
- (void)popViewControllers:(NSInteger)count {
NSArray* oldList = self.viewControllers;
NSMutableArray* newList = [NSMutableArray arrayWithArray:oldList];
if(count > [oldList count]) {
CLogError(@"Poping %d screens when there is only %d", count, [oldList count]);
count = [oldList count] - 1;
}
for(int i = 0; i<count; i++) {
[newList removeLastObject];
}
[self setViewControllers:newList animated:YES];
}
@end
¿Alguien ahora, qué podría estar haciendo mal? Me acabo de quedar sin ideas.
Además :
Ejecuté mi aplicación usando NSZombieEnabled y MallocStackLogging para descubrir qué objeto falla. Sin embargo, no dio mis resultados razonables. Para la traza de pila # 1 falla en el paso 3 ( -[UIApplication sendAction:to:from:forEvent:]
) y el objeto zombie es -[UIBarButtonItem performSelector:withObject:withObject:]: message sent to deallocated instance 0xa5f5f90
. Este es el botón de la barra de navegación derecha de la pantalla desde la cual la aplicación navega desde 2 pantallas (y recuerde, esta navegación con 2 pantallas de retroceso funciona, pero la siguiente navegación posterior "habitual" falla). Pero no hago nada con ese botón. Código correspondiente en el initWithSomething:(Something*)something
de ViewControler initWithSomething:(Something*)something
es:
UIBarButtonItem* doneItem = [[UIBarButtonItem alloc] initWithTitle:@"Complete"
style:UIBarButtonItemStyleDone
target:self action:@selector(onDone)];
self.navigationItem.rightBarButtonItem = doneItem;
[doneItem release];
Lo único especial de este botón es que el selector onDone
hace esa navegación de 2 pantallas, pero no creo que esto realmente importe. Entonces, creo que hay algo mal en el objeto de nivel superior (¿probablemente View Controller o UINavigationController?). Pero, ¿qué está mal?
Adición el 4 de octubre de 2011:
Como las personas aún a veces buscan esta pregunta, aquí hay un código. Mi enfoque actual para este problema es usar la subclase personalizada de UINavigationController en lugar de la misma con el siguiente hack (no hay garantías de que esto funcione o que aún sea necesario):
@interface CustomUINavigationController : UINavigationController {
}
@end
@implementation CustomUINavigationController
- (void)setViewControllers:(NSArray*)newStack animated:(BOOL)animated {
// HACK HACK
// Somehow everything fails if I don''t clean stack before putting new
// But on iOS4 popToRootViewControllerAnimated might call setViewControllers:animated
// let''s avoid call stack overflow
static int stackCount = 0;
if(!stackCount++) {
if([self.viewControllers count] != 1) {
[self popToRootViewControllerAnimated:NO];
}
else {
UIViewController* tmpVc = [[[UIViewController alloc] init] autorelease];
NSArray* tmpStack = [NSArray arrayWithObject:tmpVc];
[super setViewControllers:tmpStack animated:NO];
}
}
[super setViewControllers:newStack animated:animated];
stackCount--;
}
@end
Otra cosa importante: será mejor que no inicie la navegación animada mientras la navegación animada anterior aún está en progreso (es decir, al menos hasta que se llame a viewWillAppear:).
Tuve un problema similar. Resulta que, al menos en algunas circunstancias, se llama a la acción de un BarButtonItem derecho cuando se lanza un controlador de vista. Mi fea solución para esto es eliminar el elemento ofensivo cuando presiono el siguiente controlador de vista en la pila. Luego verifico en vista aparecerá si RightBarButton es nulo y recreo el botón si es necesario.
Sin embargo, al recrear el botón se colocará en 0, 0 durante una fracción de segundo antes de colocarse en su lugar en el lado derecho de la barra de navegación. Una solución ligeramente más elegante sería establecer la acción del botón en el valor predeterminado de ''NULL''. Esto resuelve el primer problema pero también romperá el BackBarButtonItem.
Para resumir, todavía estoy buscando una solución adecuada para esto. Estoy a punto de un día de trabajo de contactar a Apple con esto, incluso podría ser un error, pensándolo bien ...
Para el segundo seguimiento de pila, tuve el mismo problema. Estaba liberando el controlador de vista que contenía la vista de desplazamiento.
[mainScrollView addSubview:rubriqueController.view];
[rubriqueController release]; // Comment this line
Algo como esto.
Espero que ayude incluso 9 meses después.