Advertencia: se desaconseja la presentación de controladores de vista en controladores de vista separados

180

En mi aplicación, estoy usando un controlador de navegación. Más adelante, en alguna vista, estoy usando presentViewControllerpara mostrar una imagen ampliada. Además, no estoy usando un Storyboard o plumín.

Recibo este error solo en iOS 7. Funciona bien en iOS 6 y versiones anteriores:

Se desaconseja presentar controladores de vista en controladores de vista separados

Gagan Joshi
fuente
No me di cuenta todavía. Pero en mi aplicación no estoy asignando ningún viewcontroller a window.rootviewcontroller. Estoy agregando vista a la ventana. Puede ser que esa sea la razón para mí. pero no estoy seguro ...
Gagan Joshi
@GaganJoshi La razón que mencionó anteriormente podría no ser la causa. Incluso yo estoy enfrentando el mismo problema. Y en nuestro proyecto estoy asignando un controlador de vista a window.rootviewcontroller.
Rajesh
1
Creo que los otros comentarios relacionan correctamente esto con algo sobre rootViewController y la conexión de la ventana. No lo he entendido del todo, pero he podido solucionar el problema presentando el controlador directamente en rootViewController en lugar de hacerlo en el controlador de navegación o en uno de sus hijos.
Rich Waters
Azaxis lo consiguió: stackoverflow.com/a/31877722/5306470
Daniel Springer

Respuestas:

207

Para evitar recibir la advertencia en una navegación push, puede usar directamente:

[self.view.window.rootViewController presentViewController:viewController animated:YES completion:nil];

Y luego, en su controlador de vista modal, cuando todo haya terminado, puede llamar:

[self dismissViewControllerAnimated:YES completion:nil];

cdescours
fuente
Estoy presentando el selector de imágenes con este código de línea "[self.view.window.rootViewController presentViewController: viewController animado: SI finalización: nil];" Pero no se puede descartar la vista de puntero con esta línea "[auto-descartar ViewControllerAnimated: YES complete: nil];" Cualquier opción alternativa para despedir al controlador
kb920
@keyurbhalodiya Debe llamar al método despedsViewController desde modalView para que funcione. Entonces, si visualizaste una vista llamada viewB desde una viewA con [viewA.window.rootViewController presentViewController: viewB], en viewB necesitas agregar un botón, por ejemplo, asociado a una acción personalizada que llama a [self dispatsViewControllerAnimated]. ¿Está más claro?
cdescours
11
No presenta viewcontroller en iOS 8.
Rajesh Maurya
1
para iOS 8: [self.view.window.rootViewController.navigationController
Fede Cugliandolo
31
usando lo self.navigationControllerhizo por mí.
Brandon Zacharie
62

La razón de esta advertencia es que estaba presentando un controlador de vista sobre una vista pequeña que no es de tamaño completo. A continuación se muestra la imagen de mi proyecto. donde haga clic en cuatro opciones anteriores. El usuario navega a diferentes vistas de childviewcontroller (funciona como tabViewcontroller). Pero el childviewcontroller contiene una vista de tamaño pequeño. Entonces, si presentamos una vista desde childviewcontroller, aparece esta advertencia.

vista de detalle maestra

Y para evitar esto, puede presentar una vista sobre el padre del controlador childview

  [self.parentViewController presentViewController:viewController animated:YES completion:nil];
Gagan Joshi
fuente
1
[self.view.window.rootViewController.navigationController pushViewController: YOUR_VIEW_CONTROLER animado: SÍ];
Fede Cugliandolo
1
"presentaba un controlador de vista sobre una vista pequeña que no es de tamaño completo". ... EXACTAMENTE Buen trabajo.
Fattie
61

Esperar viewDidAppear() :

Este error también puede surgir si está intentando presentar el controlador de vista antes de que la vista realmente apareciera, por ejemplo, presentar la vista en viewWillAppear()o antes. Intenta presentar otra vista después viewDidAppear()o dentro de ella.

Azaxis
fuente
9
En otras palabras, ¡no presente ningún controlador de vista viewDidLoad(), gente! He cometido este error muchas veces ...
T Blank
Gracias, esto ayudó. Tenía un código en viewDidLoad donde intentaba mostrar un diálogo al final.
ArdenDev
Recibo este error cuando ejecuto pruebas de unidad / integración donde no pruebo con animaciones.
mixtly87
21

En mi caso, sampleViewControlleragregué una vista como una subvista, luego trato de presentar un popover desde la vista de sampleViewController(aquí, en selfcambio, una UIViewControllerinstancia):

[self.view addSubview:sampleViewController.view];

La forma correcta debería estar a continuación:

// make sure the vc has been added as a child view controller as well
[self addChildViewController:sampleViewController];
[self.view addSubview:sampleViewController.view];
[sampleViewController didMoveToParentViewController:self];

Por cierto, esto también funciona para el caso de que presente un popover desde una celda de vista de tabla, solo necesita asegurarse de que el controlador de vista de tabla también se haya agregado como controlador de vista secundario.

Kjuly
fuente
Además, llame a didMoveToParentViewController. Por favor revisa Agregar y quitar ChildViewController: gist.github.com/tomohisa/2897676
Jakehao
@jianzong Recuerdo que no hay necesidad de hacer el último paso. De cualquier manera, déjenme agregarlo, gracias por la sugerencia. :)
Kjuly
Sí, funcionará sin el último paso. Creo que el propósito es informar al parentViewController para que llame a algunos métodos para hacer algo. :)
Jakehao
2
funciona para mí, estoy usando la vista de un controlador en otro controlador - (Vista de contenedor programáticamente), no [self addChildViewController:sampleViewController];agregué, ahora agregué esto, gracias
anjnkmr
16

Creo que el problema es que no tiene una jerarquía de controlador de vista adecuada. Configure el controlador rootview de la aplicación y luego muestre nuevas vistas presionando o presentando nuevos controladores de vista en ellas. Deje que cada controlador de vista administre sus vistas. Solo los controladores de vista de contenedor, como el control de barra de pestañas, deberían agregar vistas de otros controladores de vista a sus propias vistas. Lea la guía de programación de los controladores de vista para obtener más información sobre cómo usar los controladores de vista correctamente. https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/

Daniel Ytterbrink
fuente
14

Swift 3

Para cualquiera que se encuentre con esto, aquí está la respuesta rápida.

self.parent?.present(viewController, animated: true, completion: nil)
Jeremie
fuente
9

Tengo casi el mismo problema. La razón fue que intenté presentar "algunos" controladores en otro y después de que se completó la animación, configuré el controlador presentado como root. Después de esta operación, todos los controladores adicionales que se presentan me llevan a la advertencia: " Se desaconseja presentar controladores de vista en controladores de vista separados ". Y resuelvo esta advertencia simplemente configurando "algunos" controladores como root sin ninguna presentación al comienzo.

Remoto:

[[self rootController] presentViewController:controller animated:YES completion:^{

       [self window].rootViewController = controller;

       [[self window] makeKeyAndVisible];}];

Simplemente haga como root sin ninguna presentación:

 [[self window] setRootViewController:controller];
averem
fuente
1
Este fue exactamente mi problema. Estaba tratando de presentarlo con un UIModalTransitionStyleCrossDissolve y luego hacerlo rootViewController. Después de eso, todas las otras presentaciones estaban fallando con el mensaje de advertencia dado. Simplemente configurarlo como rootViewcontroller sin animación hizo el truco. ¡Gracias!
Bernardo Oliveira
7

Una de las soluciones a esto es si tiene childviewcontroller Entonces simplemente presenta viewviewcontroller en su padre por

[self.parentViewController presentViewController:viewController animated:YES completion:nil];

Y para descartar utiliza el mismo controlador de despido.

[self dismissViewControllerAnimated:YES completion:nil];

Esta es la solución perfecta para mí.

Gagan Joshi
fuente
7

Usar [self.navigationController presentViewController:xxx animated:YES completion:nil]en iOS 8.

Tao Fang
fuente
5

Prueba este código

UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:<your ViewController object>];

[self.view.window.rootViewController presentViewController:navigationController animated:YES completion:nil];
Vlad
fuente
4

Intente presentar TabBarControllersi es una TabBarControlleraplicación basada.

[self.tabBarController presentViewController:viewController animated:YES completion:nil];

La razón podría ser selfhija de TabBarControllery está tratando de presentar desde ChildViewController.

Warif Akhand Rishi
fuente
4

Sí, también me enfrenté al mismo mensaje de advertencia mientras mostraba un controlador de alerta que estaba en otra vista. Más tarde evité esto presentando el controlador de alertas desde el controlador de vista principal como se muestra a continuación:

[self.parentViewController presentViewController:alertController animated:YES completion:nil];
Sivasagar Palakurthy
fuente
3

debe agregar el controlador de vista que presentará el nuevo controlador como hijo del controlador de vista principal.

Digamos que tiene su MainViewController, luego agrega un nuevo controlador llamado controllerA, y luego desea presentar un nuevo controlador llamado controllerB desde el controladorA

tienes que escribir algo como esto:

[self addChildViewController:controllerA]; //self is yourMainViewController
[self.view addsubView:controllerA.view]; 

y dentro del controlador A puede presentar el nuevo controlador sin advertencias

[self presentViewController:controllerB animated:YES completion:nil]; //self is controllerA
Chuy47
fuente
3

En Swift 4.1 y Xcode 9.4.1

La solucion es

DispatchQueue.main.async(execute: {
    self.present(alert, animated: true)
})

Si escribo así, obtengo el mismo error

let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in
    })
alert.addAction(defaultAction)

present(alert, animated: true, completion: nil) 

Me sale el mismo error

Presenting view controllers on detached view controllers is discouraged <MyAppName.ViewController: 0x7fa95560Z070>.

La solución completa es

let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in
     })
alert.addAction(defaultAction)
//Made Changes here    
DispatchQueue.main.async(execute: {
    self.present(alert, animated: true)
})
iOS
fuente
Ejecutarlo a través de DispatchQueue de esta manera funcionó para mí. Estoy haciendo un performSegue a un controlador de vista modal, llamado desde viewDidLoad en mi primer controlador de vista (una pantalla de introducción de primer lanzamiento para orientar a los nuevos usuarios). Se estaba cargando bien, pero generaba la advertencia. Ajustar la llamada performSegue en la llamada asíncrona DispatchQueue elimina la advertencia. ¡Gracias!
Grant Neufeld
1

Para comenzar, asegúrese de tener un controlador de vista raíz. Puedes configurarlo didFinishLaunchingWithOptions.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    [window setRootViewController:viewController];
}
samwize
fuente
1

Muchas razones para esta advertencia. El mío es porque tengo un segmento conectado de un ViewController a otro que se presentará modalmente. Pero, el ViewController desde el que presento está siendo generado dinámicamente por un PageViewController. Es por eso que está separado en el Storyboard. Mi aplicación no se bloqueará por eso; pero me gustaría silenciar la advertencia.

Lee Probert
fuente
1

Llegué a este hilo donde tengo una barra de navegación personalizada y estaba llamando a un AlertViewController a través de él.

Tuve que agregarlo de niño a mi controlador de vista principal. Entonces podría llamar a presentarlo sin previo aviso.

Deberías agregar tu Zoomed Image View Controller como hijo del ViewController principal.

(p.ej)

[self addChildViewController:ZoomedImageViewController];

Entonces podrá llamar a su ZoomedImageViewController

[self presentViewController:ZoomedImageViewController];
Naveed Abbas
fuente
1

Muchas respuestas son correctas.

  • Verifique que presentViewController tenga parentViewController o no.
  • Si no, agréguelo a algún lugar donde debería agregarse
  • de lo contrario, verifique que parentViewController tenga parentViewController recursivamente hasta que cada viewController tenga parent

Este problema me ocurrió cuando mi compañero de trabajo agregó un AViewController a BViewController. De alguna manera, simplemente agrega la vista de AViewController a la vista de BViewController.

Solucionado por add bViewController.addChild (aViewController)

Jerome Li
fuente
1
¡Gracias! agregar addChild en mi bloque de finalización Hero.shared.transition resolvió por completo mi problema.
Landnbloc
0

Depende si desea mostrar su alerta o algo similar en cualquier tipo de UIViewController.

Puede usar este ejemplo de código:

UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Alert" message:@"Example" preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:nil];

[alert addAction:cancelAction];


[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:alert animated:true completion:nil];
Fabio
fuente
Con su código, no funciona y le da este registroAttempt to present <UIAlertController: 0x7fc01a1eb600> on <ViewController: 0x7fc019821e00> whose view is not in the window hierarchy!
Naveed Abbas