Descartar un controlador de vista presentado

116

Tengo una pregunta teórica. Ahora estoy leyendo la guía ViewController de Apple .

Ellos escribieron:

Cuando llega el momento de descartar un controlador de vista presentado, el enfoque preferido es dejar que el controlador de vista de presentación lo descarte. En otras palabras, siempre que sea posible, el mismo controlador de vista que presentó el controlador de vista también debe asumir la responsabilidad de descartarlo. Aunque existen varias técnicas para notificar al controlador de vista de presentación que su controlador de vista presentado debe descartarse, la técnica preferida es la delegación.

Pero no puedo explicar por qué tengo que crear un protocolo en el VC presentado y agregar la variable delegada, crear un método delegado al presentar VC para descartar el VC presentado, en lugar de una simple llamada en el método del controlador de vista presentado

[self dismissViewControllerAnimated:NO completion:nil]?

¿Por qué es mejor la primera opción? ¿Por qué Apple lo recomienda?

nikitahils
fuente

Respuestas:

122

Creo que Apple se está cubriendo un poco la espalda aquí por una API potencialmente torpe.

  [self dismissViewControllerAnimated:NO completion:nil]

En realidad es un poco un violín. Aunque puede, legítimamente, llamar a esto en el controlador de vista presentado, todo lo que hace es reenviar el mensaje al controlador de vista de presentación. Si desea hacer algo más allá de simplemente descartar el VC, necesitará saber esto, y debe tratarlo de la misma manera que un método delegado, ya que eso es más o menos lo que es, un método integrado algo inflexible método delegado.

Tal vez se hayan encontrado con un montón de código incorrecto por parte de personas que no comprenden realmente cómo se arma, de ahí su precaución.

Pero, por supuesto, si todo lo que necesita hacer es descartar el asunto, adelante.

Mi propio enfoque es un compromiso, al menos me recuerda lo que está sucediendo:

  [[self presentingViewController] dismissViewControllerAnimated:NO completion:nil]

[Rápido]

  self.presentingViewController?.dismiss(animated: false, completion:nil)
fundición
fuente
26
Cabe señalar que el uso presentingViewControlleres en su mayoría inútil, ya que se referirá a UINavigationControllersi selfestá incrustado en uno. En cuyo caso, no podrá obtener el presentingViewController. Sin embargo, [self dismissViewControllerAnimated:completion]todavía funciona en ese caso. Mi sugerencia sería continuar usándolo hasta que Apple lo arregle.
memmons
4
Me encanta que esta respuesta siga siendo totalmente relevante 3 años después.
user1021430
1
Otra cosa a considerar es que un controlador de vista no sabe cómo se mostró. Podría haber sido presentado, insertado en un controlador de navegación, parte de un controlador de barra de pestañas, etc. El uso del delegado permite que el controlador de vista "presentando" "descarte" el controlador de vista usando el inverso de cualquier método que se haya usado para presentarlo.
David Smith
51

Actualizado para Swift 3

Vine aquí solo queriendo descartar el controlador de vista actual (presentado). Estoy dando esta respuesta para cualquiera que venga aquí con el mismo propósito.

Controlador de navegación

Si está utilizando un controlador de navegación, entonces es bastante fácil.

Regrese al controlador de vista anterior:

// Swift
self.navigationController?.popViewController(animated: true)

// Objective-C
[self.navigationController popViewControllerAnimated:YES];

Regrese al controlador de vista raíz:

// Swift
self.navigationController?.popToRootViewController(animated: true)

// Objective-C
[self.navigationController popToRootViewControllerAnimated:YES];

(Gracias a esta respuesta para el Objective-C.)

Controlador de vista modal

Cuando un controlador de vista se presenta de forma modal, puede descartarlo (desde el segundo controlador de vista) llamando

// Swift
self.dismiss(animated: true, completion: nil)

// Objective-C
[self dismissViewControllerAnimated:YES completion:nil];

La documentación dice,

El controlador de vista de presentación es responsable de descartar el controlador de vista que presentó. Si llama a este método en el controlador de vista presentado, UIKit le pide al controlador de vista de presentación que maneje el rechazo.

Así que funciona para que el controlador de vista presentado lo llame sobre sí mismo. aquí muestra un ejemplo completo.

Delegados

La pregunta del OP era sobre la complejidad de usar delegados para rechazar una opinión.

Hasta este punto, no he necesitado usar delegados, ya que generalmente tengo un controlador de navegación o controladores de vista modal, pero si necesito usar el patrón de delegado en el futuro, agregaré una actualización.

Suragch
fuente
50

Esto es para la reutilización del controlador de vista.

A su controlador de vista no debería importarle si se presenta como modal, si se presiona en un controlador de navegación o lo que sea. Si su controlador de vista se descarta, entonces está asumiendo que se presenta de forma modal. No podrá insertar ese controlador de vista en un controlador de navegación.

Al implementar un protocolo, deja que el controlador de vista principal decida cómo debe presentarse / presionarse y descartarse / aparecer.

Michael Enríquez
fuente
7

prueba esto:

[self dismissViewControllerAnimated:true completion:nil];
Oshitha Wimalasuriya
fuente
6

En mi experiencia, es útil cuando necesita descartarlo de cualquier ViewController que desee y realizar diferentes tareas para cada viewcontroller que lo descarta. Cualquier viewController que adopte el protocolo puede descartar la vista a su manera. (ipad vs iphone, o pasar datos diferentes al descartar desde diferentes vistas, llamar a diferentes métodos al descartar, etc.)

Editar:

Entonces, para aclarar, si todo lo que quiere hacer es descartar la vista, no veo la necesidad de configurar el protocolo de delegado. Si necesita hacer cosas diferentes después de descartarlo desde diferentes controladores de vista de presentación, sería la mejor manera de usar el delegado.

jhilgert00
fuente
pero si no necesito "pasar datos diferentes al descartar desde diferentes vistas, llamar a métodos diferentes al descartar, etc.", ¿puedo hacer una pequeña llamada en el método del controlador de vista presentado - [autodespedidoViewControllerAnimated: NO completado: nulo]?
Nikitahils
Dejar que el presentador descarte la vista presentada hace que sea obvio que el presentador de hecho está listo y manejando el regreso al primer plano: la secuencia de ejecución es fácil de seguir y la responsabilidad de cualquier actualización de la interfaz de usuario está implícitamente clara.
Johan
2

Cita de la Guía de programación del controlador de vista , "Cómo los controladores de vista presentan otros controladores de vista".

Cada controlador de vista en una cadena de controladores de vista presentados tiene punteros a los otros objetos que lo rodean en la cadena. En otras palabras, un controlador de vista presentado que presenta otro controlador de vista tiene objetos válidos tanto en sus propiedades presentViewController como presentViewController. Puede utilizar estas relaciones para rastrear la cadena de controladores de vista según sea necesario. Por ejemplo, si el usuario cancela la operación actual, puede eliminar todos los objetos de la cadena descartando el primer controlador de vista presentado. Descartar un controlador de vista descarta no solo ese controlador de vista, sino también cualquier controlador de vista que haya presentado.

Entonces, por un lado, tiene un diseño agradable y equilibrado, un buen desacoplamiento, etc. Pero, por otro lado, es muy práctico, porque puede volver rápidamente a un punto determinado de la navegación.

Aunque, personalmente preferiría usar segues de desenrollado que intentar atravesar hacia atrás el árbol de controladores de vista de presentación , que es de lo que habla Apple en este capítulo de donde proviene la cita.

svena
fuente
2

Un punto es que este es un buen enfoque de codificación. Satisface a muchosOOP principios, por ejemplo, SRP, Separación de preocupaciones, etc.

Por lo tanto, el controlador de vista que presenta la vista debería ser el que la descarte.

Por ejemplo, una empresa de bienes raíces que cede una casa en alquiler debería ser la autoridad para recuperarla.

Abdurrahman Mubeen Ali
fuente
2

Swift 3.0 // Descartar el controlador de vista rápidamente

self.navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
Pranit
fuente
1

Además de la respuesta de Michael Enriquez, puedo pensar en otra razón por la que esta puede ser una buena manera de protegerse de un estado indeterminado:

Digamos que ViewControllerA presenta ViewControllerB modalmente. Pero, dado que es posible que no haya escrito el código para ViewControllerA, no conoce el ciclo de vida de ViewControllerA. Puede descartar 5 segundos (digamos) después de presentar su controlador de vista, ViewControllerB.

En este caso, si simplemente estuviera usando dismissViewController ViewControllerB para descartarse, terminaría en un estado indefinido, tal vez no en un bloqueo o una pantalla negra, sino en un estado indefinido desde su punto de vista.

Si, en cambio, estuviera usando el patrón de delegado, estaría al tanto del estado de ViewControllerB y podría programar para un caso como el que describí.

Mayur
fuente
1

Rápido

let rootViewController:UIViewController = (UIApplication.shared.keyWindow?.rootViewController)!

        if (rootViewController.presentedViewController != nil) {
            rootViewController.dismiss(animated: true, completion: {
                //completion block.
            })
        }
Rishi Chaurasia
fuente
0

Si está utilizando la vista de uso modal, descarte.

[self dismissViewControllerAnimated:NO completion:nil];
ErasmoOliveira
fuente
¿Cómo responde esto a la pregunta: "¿Por qué es mejor la primera opción? ¿Por qué Apple la recomienda?"
jww
0

Esto es un montón de tonterías. La delegación está bien cuando se necesita, pero si hace que el código sea más complejo, y lo hace, entonces debe haber una razón para ello.

Estoy seguro de que Apple tiene sus razones. Pero es más claro y conciso simplemente hacer que el CV presentado haga el descarte, a menos que haya una verdadera razón para hacer lo contrario y nadie aquí a día de hoy ha presentado una que yo pueda ver.

Los protocolos son excelentes cuando se necesitan, pero el diseño orientado a objetos nunca se trató de que los módulos se comunicaran innecesariamente entre sí.

Tom Love (co-desarrollador de Objective C) comentó una vez que Objective C era "elegante", "pequeño", "nítido" y "bien definido" (en comparación con C ++). Fácil de decir para él. La delegación es una característica útil que parece haber sido utilizada en exceso "solo porque sí", y aunque me gusta trabajar en el idioma, temo la idea de sentirme obligado a usar una sintaxis innecesaria para hacer las cosas más complejas de lo que tienen que ser.

Expresión regular
fuente
Puede que le ahorre algo de código inicialmente, pero su enfoque le causará muchos dolores de cabeza a medida que su base de código crezca. Debe comprender los principios orientados a objetos, como la separación de preocupaciones, de lo contrario, también podría codificar toda la aplicación en un archivo grande.
Werner Altewischer
-2

Puedes cerrar tu ventana de super vista

self.view.superview?.window?.close()

Código de señor
fuente