iphone - UISearchDisplayController provoca bloqueo después de viewDidUnload
uistoryboard (7)
¿Por qué no usas self.searchDisplayController solamente?
Ya lo he usado muchas veces, no creará ningún problema. También puedes personalizar eso si lo deseas.
Tengo un proyecto que utiliza StoryBoards y UISearchDisplayController
en el contexto de un UINavigationController
, que aparece en el controlador de vista raíz. Cuando presiono un nuevo controlador de vista en la pila y causo una advertencia de memoria simulada (o en realidad recibo una advertencia de memoria baja). El controlador de vista anterior descarga con éxito su vista. Sin embargo, cuando EXC_BAD_ACCESS
el segundo controlador de vista de la pila, obtengo un EXC_BAD_ACCESS
. Encendí NSZombies y descubrí esto:
[UISearchDisplayController retain]: mensaje enviado a la instancia desasignada 0xb13aa30
No estoy (al menos en mi código) enviando ese mensaje al UISearchDisplayController
. No estoy haciendo nada, hablando programáticamente, con eso. Los puntos de ruptura revelan que ni siquiera estoy viewDidLoad
del primer controlador de vista.
Algo curioso, sin embargo: para las risas y las risitas, decidí retain
completamente el SDC en mi punto de vista viewDidLoad
, solo para ver qué pasaría y no se produciría ningún fallo. Sin embargo, mi instancia de UISearchDisplayController
es nil
.
Hice un backtrace y obtuve esta salida:
#0 0x01e30e1e in ___forwarding___ ()
#1 0x01e30ce2 in __forwarding_prep_0___ ()
#2 0x01dd1490 in CFRetain ()
#3 0x01eb69c0 in +[__NSArrayI __new::] ()
#4 0x01e0a00a in -[__NSPlaceholderArray initWithObjects:count:] ()
#5 0x01e34f52 in +[NSArray arrayWithObjects:count:] ()
#6 0x01e5e084 in -[NSDictionary allValues] ()
#7 0x01035272 in -[UINib instantiateWithOwner:options:] ()
#8 0x00edce2c in -[UIViewController _loadViewFromNibNamed:bundle:] ()
#9 0x00edd3a9 in -[UIViewController loadView] ()
#10 0x00edd5cb in -[UIViewController view] ()
#11 0x00edd941 in -[UIViewController contentScrollView] ()
#12 0x00eef47d in -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:] ()
#13 0x00eef66f in -[UINavigationController _layoutViewController:] ()
#14 0x00eef93b in -[UINavigationController _startTransition:fromViewController:toViewController:] ()
#15 0x00ef03df in -[UINavigationController _startDeferredTransitionIfNeeded] ()
#16 0x00ef16cb in _popViewControllerNormal ()
#17 0x00ef196c in -[UINavigationController _popViewControllerWithTransition:allowPoppingLast:] ()
#18 0x0b446e82 in -[UINavigationControllerAccessibility(SafeCategory) _popViewControllerWithTransition:allowPoppingLast:] ()
#19 0x00ef0b10 in -[UINavigationController popViewControllerAnimated:] ()
#20 0x00ef297d in -[UINavigationController navigationBar:shouldPopItem:] ()
#21 0x00e7dabe in -[UINavigationBar _popNavigationItemWithTransition:] ()
#22 0x00e7da49 in -[UINavigationBar popNavigationItemAnimated:] ()
#23 0x0b42208c in -[UINavigationBarAccessibility(SafeCategory) popNavigationItemAnimated:] ()
#24 0x00e80507 in -[UINavigationBar _handleMouseUpAtPoint:] ()
#25 0x00e8074c in -[UINavigationBar touchesEnded:withEvent:] ()
#26 0x00e3fa30 in -[UIWindow _sendTouchesForEvent:] ()
#27 0x00e3fc56 in -[UIWindow sendEvent:] ()
#28 0x00e26384 in -[UIApplication sendEvent:] ()
#29 0x00e19aa9 in _UIApplicationHandleEvent ()
#30 0x02d37fa9 in PurpleEventCallback ()
#31 0x01e9e1c5 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
#32 0x01e03022 in __CFRunLoopDoSource1 ()
#33 0x01e0190a in __CFRunLoopRun ()
#34 0x01e00db4 in CFRunLoopRunSpecific ()
#35 0x01e00ccb in CFRunLoopRunInMode ()
#36 0x02d36879 in GSEventRunModal ()
#37 0x02d3693e in GSEventRun ()
#38 0x00e17a9b in UIApplicationMain ()
#39 0x00002b72 in main (argc=1, argv=0xbffff620)
No parece haber nada realmente interesante allí (¿hay alguna vez?: P) y parece ser todo lo interno de Apple. ¿Alguna idea sobre cómo hacer que este problema desaparezca?
ACTUALIZACIÓN: Incluso cuando elimino la conexión entre mi controlador de vista y la propiedad del Controlador de pantalla de búsqueda pero creo mi propio IBOutlet
, aún se bloquea. Bad bug quizás?
ACTUALIZACIÓN 2: Cuando creo mi propia instancia de un UISearchDisplayController
mediante UISearchDisplayController
(no a través del guión gráfico) y lo creo en viewDidLoad
, todo funciona de la manera que se supone.
ACTUALIZACIÓN 3: Puedo reproducir este problema de manera consistente en un nuevo proyecto con un guión gráfico. Hice lo mismo con una punta de vainilla y todo funcionó como se suponía. Sin embargo, si configuro lo mismo utilizando un guión gráfico y un segmento, se explota como lo hace en mi proyecto real. :(
RECUPERAR : Aquí están los pasos para recrear este problema:
- Cree un controlador de vista en un guión gráfico con un
UISearchDisplayController
- Presiona un nuevo controlador de vista en la pila de navegación
- Causa una advertencia de memoria baja
- Pop el controlador de la pila
- KABOOM!
viewDidLoad
ni siquiera recibe una llamada en el primer controlador de vista en este punto, el código de Apple explota antes de esa fecha.
@Wayne: Me había topado con el mismo problema con un SearchDisplayController creado a partir de un Storyboard, y pasé más de un día intentando depurar un bloqueo que parecía aparecer cuando ninguno de mis códigos se estaba ejecutando. En mi caso, el síntoma fue que el usuario pulsa una pestaña en UITabBarController para volver a un ViewController que se ha descargado después de una advertencia de memoria. El método viewDidLoad del controlador de vista descargado nunca se ejecuta y el código llega al menos a tabBarController: didSelectViewController: (que debería ejecutarse después de viewDidLoad) antes de que se bloquee en algún lugar del código de ensamblaje.
Gracias masivamente por publicar esta solución y por todos los seguimientos. Una pequeña mejora es mover su instanciación UIDisplayController a un método de acceso cargado perezosamente para la propiedad searchDisplayController. El efecto práctico es insignificante, pero se ve mejor!
Esto es lo que hice (concedido, es una solución y no una solución para el error de Apple):
Primero, en un UIViewController
base, creé una propiedad llamada searchController
:
@property (nonatomic, retain) IBOutlet UISearchDisplayController* searchController;
UISearchBar
una UISearchBar
en el constructor de interfaces para tener un marcador de posición en mi interfaz de usuario. Luego, en mi viewDidLoad
, configuro manualmente el controlador y lo viewDidLoad
:
UISearchDisplayController* searchController = [[UISearchDisplayController alloc]
initWithSearchBar:self.searchBar contentsController:self];
searchController.searchResultsDataSource = self;
searchController.searchResultsDelegate = self;
searchController.delegate = self;
self.searchController = searchController;
[searchController release];
En mi viewDidUnload
me aseguro de borrarlo:
self.searchController = nil;
Hasta ahora, encontré esta solución de trabajo para iOS 5 SDK utilizando ARC:
en el archivo .h, declare su propia propiedad searchDisplayController con IBOutlet
@property (strong, nonatomic) IBOutlet UISearchDisplayController * searchDisplayController;
Luego, en el archivo .m, sintetízalo:
@synthesize searchDisplayController;
Pero no lo establezca en nulo en viewDidUnload.
De modo que el controlador de visualización de búsqueda usará la propiedad que cree en lugar de usar la propiedad heredada.
También me doy cuenta de que también aparece un error similar para los reconocedores de gestos (si creas reconocedores de gestos desde el guión gráfico en lugar de crearlos de forma programada). También necesitamos crear las propiedades del reconocedor de gestos FUERTES y enlazarlos con los objetos del reconocedor de gestos que creas en el guión gráfico. Luego, en viewDidUnload, no los establezca en nil. <- esto evita los choques.
Un punto importante a tener en cuenta, es que los bloqueos de este tipo pueden ocurrir si abandona la vista mientras su searchDisplayController todavía está activo. Este es el problema que estaba teniendo, al seleccionar un elemento en searchDisplayController se configuró para sacar el controlador de vista de la pila, para solucionarlo, tuve que incluir el siguiente código antes de que se abriera la vista ...
if (self.searchDisplayController.active) {
[self.searchDisplayController setActive:NO];
}
ViewDidUnload Called significa que tienes excepciones de memoria en tu aplicación.
Primero intente solucionar los problemas de memoria, luego, la búsqueda automáticamente se resolverá.
Debido a que parece que no hay nada de malo en el código, cuando se producen excepciones de memoria, es mejor tomar la pantalla anterior del usuario diciendo [self.navigationController popViewControllerAnimated:NO]
Explicitly declare your outlet
@property (nonatomic, strong) IBOutlet UISearchDisplayController *searchDisplayController;
Then in dealloc - add these lines - nil out the delegate / data source so that they do not receive any message further when the searchDisplayController deallocates itself.
self.searchDisplayController.delegate = nil;
self.searchDisplayController.searchResultsDelegate = nil;
self.searchDisplayController.searchResultsDataSource = nil;