Descartar un controlador de vista presentado

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 presente lo descarte. En otras palabras, siempre que sea posible, el mismo controlador de vista que presentó el controlador de vista también debería asumir la responsabilidad de descartarlo. Aunque hay varias técnicas para notificar al controlador de vista que presenta 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 VC presentado y agregar varible delegado, crear un método de delegado al presentar VC para descartar el VC presentado, en lugar de una simple llamada en el método de vista del controlador presentado

[self dismissViewControllerAnimated:NO completion:nil] ?

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

Creo que Apple está cubriendo sus espaldas un poco aquí por una pieza de API potencialmente kludgy.

  [self dismissViewControllerAnimated:NO completion:nil] 

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

Tal vez se encontraron con un montón de códigos erróneos por parte de personas que no entendían realmente cómo se organiza esto, de ahí su precaución.

Pero, por supuesto, si todo lo que tiene que hacer es descartar la cosa, 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) 

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

Su controlador de vista no debería importar si se presenta como un modal, empujado en un controlador de navegación, o lo que sea. Si su controlador de vista se descarta a sí mismo, está asumiendo que se presenta de forma modal. No podrá presionar ese controlador de vista en un controlador de navegación.

Al implementar un protocolo, permite que el controlador de vista padre decida cómo debe ser presentado / empujado y descartado / reventado.

Actualizado para Swift 3

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

Controlador de navegación

Si está usando 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 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 propio controlador de vista presentado, UIKit le pide al controlador de vista que presente que se encargue del despido.

Por lo tanto, funciona para el controlador de vista presentado llamarlo solo. Aquí hay un ejemplo completo.

Delegados

La pregunta del OP era sobre la complejidad de usar delegates para descartar una vista.

  • Esta respuesta de Objective-C entra un poco.
  • Aquí hay un ejemplo de Swift.

Hasta este punto no he necesitado usar delegates 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.

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

Editar:

Entonces, para aclarar, si todo lo que desea hacer es descartar la vista, no veo la necesidad de configurar el protocolo de delegado. Si necesita hacer cosas diferentes después de descartarlo de los diferentes controladores de vista que se presentan, sería la mejor manera de utilizar el delegado.

prueba esto:

 [self dismissViewControllerAnimated:true completion:nil]; 

Cita de la Guía de progtwigción del controlador de visualización , “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 de presentaciónViewController como presentedViewController. Puede usar estas relaciones para rastrear a través de 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 presente.

Por lo tanto, por un lado, es un diseño equilibrado, buen desacoplamiento, etc. Por otro lado, es muy práctico, ya que puede volver rápidamente a un determinado punto de navegación.

Aunque, yo personalmente preferiría usar desenrollados que tratar de atravesar el árbol de controladores de visualización , que es de lo que Apple habla en este capítulo de donde proviene la cita.

Un punto es que este es un buen enfoque de encoding. Satisface muchos principios de OOP , por ejemplo, SRP, separación de preocupaciones, etc.

Entonces, el controlador de vista que presenta la vista debe ser el que lo descarta.

Al igual, una compañía de bienes raíces que alquila una casa debe ser la autoridad para recuperarla.

Swift 3.0 // Descartar el controlador de vista en swift

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

Si está utilizando el uso modal, deséchelo.

 [self dismissViewControllerAnimated:NO completion:nil]; 

Esto es mucha tontería. La delegación está bien cuando es necesaria, pero si hace que el código sea más complejo, y lo es, entonces tiene que haber una razón para ello.

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

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

Tom Love (co-desarrollador de Objective C) una vez comentó que Objective C era “elegante”, “pequeño”, “nítido” y “bien definido” (cuando se compara con C ++). Es fácil para él decirlo. La delegación es una característica útil que parece haber sido usada en exceso “solo porque”, y aunque me gusta trabajar en el lenguaje, me aterroriza la idea de sentirse obligado a utilizar una syntax innecesaria para hacer las cosas más complejas de lo que deben ser.

Además de la respuesta de Michael Enríquez, puedo pensar en otra razón por la cual esta puede ser una buena forma de protegerse de un estado indeterminado:

Digamos que ViewControllerA presenta ViewControllerB de forma modal. 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 (por ejemplo) después de presentar su controlador de vista, ViewControllerB.

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

Si, en cambio, estuvieras usando el patrón de delegado, estarías al tanto del estado de ViewControllerB y puedes progtwigr para un caso como el que describí.

Rápido

 let rootViewController:UIViewController = (UIApplication.shared.keyWindow?.rootViewController)! if (rootViewController.presentedViewController != nil) { rootViewController.dismiss(animated: true, completion: { //completion block. }) } 

Puedes cerrar tu ventana de súper vista

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