Recibí este informe de bloqueo, pero no sé cómo depurarlo.
Fatal Exception NSInvalidArgumentException
Can't add self as subview
0 ... CoreFoundation __exceptionPreprocess + 130
1 libobjc.A.dylib objc_exception_throw + 38
2 CoreFoundation -[NSException initWithCoder:]
3 UIKit -[UIView(Internal) _addSubview:positioned:relativeTo:] + 110
4 UIKit -[UIView(Hierarchy) addSubview:] + 30
5 UIKit __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke + 1196
6 UIKit +[UIView(Animation) performWithoutAnimation:] + 72
7 UIKit -[_UINavigationParallaxTransition animateTransition:] + 732
8 UIKit -[UINavigationController _startCustomTransition:] + 2616
9 UIKit -[UINavigationController _startDeferredTransitionIfNeeded:] + 418
10 UIKit -[UINavigationController __viewWillLayoutSubviews] + 44
11 UIKit -[UILayoutContainerView layoutSubviews] + 184
12 UIKit -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 346
13 QuartzCore -[CALayer layoutSublayers] + 142
14 QuartzCore CA::Layer::layout_if_needed(CA::Transaction*) + 350
15 QuartzCore CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 16
16 QuartzCore CA::Context::commit_transaction(CA::Transaction*) + 228
17 QuartzCore CA::Transaction::commit() + 314
18 QuartzCore CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 56
La versión de iOS es 7.0.3. ¿Alguien experimenta este extraño accidente?
ACTUALIZAR:
No sé en qué parte de mi código causó este bloqueo, así que no puedo publicar el código aquí, lo siento.
Segunda ACTUALIZACIÓN
Vea la respuesta a continuación.
ios
iphone
objective-c
Arnol
fuente
fuente
Respuestas:
Estoy especulando sobre la base de algo similar que depuré recientemente ... si presionas (o haces estallar) un controlador de vista con Animated: SÍ no se completa de inmediato, y suceden cosas malas si haces otro push o pop antes de la animación completa. Puede probar fácilmente si este es realmente el caso cambiando temporalmente sus operaciones Push y Pop a Animated: NO (para que se completen sincrónicamente) y ver si eso elimina el bloqueo. Si este es realmente su problema y desea volver a activar la animación, entonces la estrategia correcta es implementar el protocolo UINavigationControllerDelegate. Esto incluye el siguiente método, que se llama después de completar la animación:
Básicamente, desea mover algo de código según sea necesario a este método para asegurarse de que no se produzcan otras acciones que puedan causar un cambio en la pila NavigationController hasta que finalice la animación y la pila esté lista para más cambios.
fuente
[newViewController setLabelTitle:...]
usuario del nuevo controlador de vista justo después de llamar a pushViewController conAnimated:YES.
Y resolví mover el método setLabelTitle para verDidLoad en el nuevo ViewController. Gracias por darme la pista.También comenzamos a tener este problema, y era muy probable que los nuestros fueran causados por el mismo problema.
En nuestro caso, tuvimos que extraer datos del back-end en algunos casos, lo que significaba que un usuario podía tocar algo y luego habría un ligero retraso antes de que ocurriera el empuje de navegación. Si un usuario estaba haciendo tapping rápidamente, podría terminar con dos pulsaciones de navegación desde el mismo controlador de vista, lo que provocó esta misma excepción.
Nuestra solución es una categoría en UINavigationController que evita los empujes / estallidos a menos que el vc superior sea el mismo desde un punto dado en el tiempo.
archivo .h:
archivo .m:
Hasta ahora, esto parece haber resuelto el problema para nosotros. Ejemplo:
Básicamente, la regla es: antes de cualquier retraso no relacionado con el usuario tome un bloqueo del controlador de navegación relevante e inclúyalo en la llamada para pulsar / abrir.
La palabra "bloqueo" puede ser una redacción ligeramente pobre, ya que puede insinuar que hay alguna forma de bloqueo que necesita desbloqueo, pero como no hay un método de "desbloqueo" en ningún lado, probablemente esté bien.
(Como nota al margen, "demoras no relacionadas con el usuario" son cualquier demora que el código está causando, es decir, cualquier cosa asincrónica. Los usuarios que tocan un controlador de navegación que se empuja animadamente no cuentan y no hay necesidad de hacer la versión navigationLock: para esos casos.)
fuente
Este código resuelve el problema: https://gist.github.com/nonamelive/9334458
Utiliza una API privada, pero puedo confirmar que es seguro en App Store. (Una de mis aplicaciones que usa este código fue aprobada por la App Store).
fuente
Describiré más detalles sobre este bloqueo en mi aplicación y lo marcaré como respondido.
Mi aplicación tiene un UINavigationController con el controlador raíz es un UITableViewController que contiene una lista de objetos de nota. El objeto de nota tiene una propiedad de contenido en html. Seleccione una nota que irá al controlador de detalles.
Controlador de detalle
Este controlador tiene un UIWebView, muestra el contenido de la nota pasada desde el controlador raíz.
Este controlador es el delegado del control webview. Si la nota contiene enlaces, toque un enlace que irá al navegador web integrado en la aplicación.
Recibí el informe de bloqueo anterior todos los días. No sé en qué parte de mi código causó este bloqueo. Después de algunas investigaciones con la ayuda de un usuario, finalmente pude solucionar este bloqueo. Este contenido html provocará el bloqueo:
En el método viewDidLoad del controlador de detalles, cargué este html en el control webview, justo después de eso, el método delegado anterior se llamó inmediatamente con request.URL es la fuente del iframe (google.com). Este método delegado llama al método pushViewController mientras está en viewDidLoad => crash!
Solucioné este bloqueo marcando el tipo de navegación:
Espero que esto ayude
fuente
viewDidLoad
?Tuve el mismo problema, lo que simplemente funcionó para mí fue cambiar Animated: Yes a Animated: No.
Parece que el problema se debió a que la animación no se completó a tiempo.
Espero que esto ayude a alguien.
fuente
Para reproducir este error, intente presionar dos controladores de vista al mismo tiempo. O empujando y haciendo estallar al mismo tiempo. Ejemplo:
He creado una categoría que intercepta estas llamadas y las hace seguras asegurándose de que no haya otros empujes mientras uno está en progreso. Simplemente copie el código en su proyecto y, debido al método swizzling, estará listo.
fuente
popToRootViewController
opopToViewController:
cuando ya está en el controlador de vista raíz o en el control viewController,didShowViewController
no se llamará y quedará bloqueadoviewTransitionInProgress
.self.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)viewController; [self.interactivePopGestureRecognizer setEnabled:YES];
cuándo se deshabilitó el reconocedor? ¿Y cómo sabes cuál debería ser el delegado? Con esas líneas, para mí rompe el gesto de pop después de aparecer una vez.Acabo de experimentar este problema también. Déjame mostrarte mi código:
El error aparece debido a esta línea:
No puede agregarse a la subvista. Cambié la línea de código a:
El error desapareció y pude ver ambas vistas. Solo pensé que esto ayudaría a cualquiera que quisiera ver un ejemplo.
fuente
Busque su código para "addSubview".
En uno de los lugares a los que llamó este método, trató de agregar una vista a su propia matriz de subvista utilizando este método.
Por ejemplo:
O:
fuente
[View2.view addSubview:View2.view]
tanto, se agregó self como subview.Creo que presionar / hacer estallar los controladores de vista con animación en cualquier punto debería estar perfectamente bien y el SDK debería manejar gentilmente la cola de llamadas para nosotros.
Por lo tanto, no lo hace y todas las soluciones intentan ignorar los impulsos posteriores, lo que podría considerarse un error ya que la pila de navegación final no es lo que pretendía el código.
Implementé una cola de llamadas push en su lugar:
No maneja colas mixtas de push y pops, pero es un buen comienzo para solucionar la mayoría de nuestros bloqueos.
Gist: https://gist.github.com/rivera-ernesto/0bc628be1e24ff5704ae
fuente
Perdón por llegar tarde a la fiesta. Recientemente tuve este problema en el que mi barra de navegación entra en estado dañado debido a que presiono más de un controlador de vista al mismo tiempo. Esto sucede porque el otro controlador de vista se presiona mientras el primer controlador de vista todavía está animando. Tomando una pista de la respuesta no acertada, se me ocurrió una solución simple que funciona en mi caso. Solo necesita subclasificar
UINavigationController
y anular el método pushViewController y verificar si la animación del controlador de vista anterior ya ha finalizado. Puede escuchar la finalización de la animación haciendo que su clase sea un delegadoUINavigationControllerDelegate
y establezca el delegado enself
.He subido una esencia aquí para simplificar las cosas.
Solo asegúrese de establecer esta nueva clase como NavigationController en su guión gráfico.
fuente
Basado en la gran sugerencia de @RobP, hice la subclase UINavigationController para evitar tales problemas. Maneja empujar y / o hacer estallar y puede ejecutar con seguridad:
Si la marca 'acceptConflictingCommands' es verdadera (de forma predeterminada), el usuario verá el empuje animado de vc1, vc2, vc3 y luego verá el estallido animado de vc3. Si 'acceptConflictingCommands' es falso, todas las solicitudes push / pop se descartarán hasta que vc1 se presione completamente, por lo que se descartarán otras 3 llamadas.
fuente
animated:true
flag?La solución de nonamelive es asombrosa. Pero si no desea utilizar la API privada, simplemente puede lograr el
UINavigationControllerDelegate
método o puede cambiar la animaciónYES
aNO
. Aquí hay una muestra de código, puede heredarlo. Espero que sea útil :)https://github.com/antrix1989/ANNavigationController
fuente
Había buscado mucho este problema, tal vez presionando dos o más VC al mismo tiempo, lo que causa el problema de animación de empuje, puede referirse a esto: No se puede agregar a mí mismo como subvista 崩溃 解决 办法
solo asegúrese de que haya un VC en el progreso de la transición al mismo tiempo, buena suerte.
fuente
Algunas veces, por error, trató de agregar una vista a su propia vista.
cambie esto a su vista secundaria.
fuente
También me encontré con este problema. Cuando hice el análisis de registro de Firebase, descubrí que este problema solo ocurre cuando la aplicación se inicia en frío. Así que escribí una demostración que puede reproducir este bloqueo.
.
También descubrí que cuando se muestra el controlador de vista raíz de la ventana, realizar varios empujes no causará el mismo problema nuevamente. (Puede comentar testColdStartUp (rootNav) en AppDelegate.swift y descomentar el comentario testColdStartUp () en ViewController.swift)
PD: analicé la escena de este bloqueo en mi aplicación. Cuando el usuario hace clic en la notificación de inserción para iniciar en frío la aplicación, la aplicación todavía está en la página de inicio y hace clic en otra inserción para saltar. En este momento, la aplicación puede aparecer el bloqueo. Mi solución actual es almacenar en caché el inicio en frío del enlace universal o de inserción para abrir la página de salto de la aplicación, esperar a que se muestre el controlador rootview y luego retrasar la ejecución.
fuente
pruebe su navegación usando el método de retraso, para completar la última animación de navegación,
[self performSelector:<#(SEL)#> withObject:<#(id)#> afterDelay:<#(NSTimeInterval)#>]
fuente
Una vista no se puede agregar como una subvista en sí misma.
Las vistas mantienen una jerarquía de elementos primarios y secundarios, por lo que si agrega una vista como una subvista en sí misma, lo hará por excepción.
si una clase es UIViewController, para obtener su vista, use self.view.
si una clase es UIView Class, entonces para obtener su vista, usa self.
fuente
no puede agregar self como subview si va a ser una clase UiViewController. puede agregar self como subview si va a ser una clase UiView.
fuente
Si desea agregar una Subvista a una Vista, puede hacerlo así;
fuente