¿Cómo eliminar los controlleres de vista en cualquier momento (incluso durante las transiciones) o cuando es seguro descartar un controller de vista?

Tengo una aplicación de iOS que tiene una connection a un server. Si nos desconectamos, quiero poder descartar los controlleres de vista superior para volver a un controller de vista de "connection al server". El problema es que puede producirse una desconnection en cualquier momento, incluso durante una transición entre los controlleres de vista.

La jerarquía del controller de vista es similar:

  1. ConnectingToServerViewController
  2. SignInViewController
  3. MainAppViewController
  4. Otros controlleres de vista

Cuando se detecta una desconnection, quiero que la jerarquía de la vista vuelva a queuepsar:

  1. ConnectingToServerViewController

Entonces, cuando se detecta una desconnection, se llama a este método en ConnectingToServerViewController para descartar cualquier cosa que haya presentado y volver a intentar conectarse al server:

 - (void)restartSession { if (self.presentedViewController) { [self dismissViewControllerAnimated:NO completion:nil]; } } 

Sin embargo, si bash descartar mientras se produce una transición de vista, obtengo errores como

 *** Assertion failure in -[UIWindowController transition:fromViewController:toViewController:target:didEndSelector:], /SourceCache/UIKit/UIKit-2380.17/UIWindowController.m:211 attempt to dismiss modal view controller whose view does not currently appear. self = <YYYYYViewController: 0x2089c8a0> modalViewController = <XXXXXViewController: 0x208e6610> attempt to dismiss modal view controller whose view does not currently appear. self = <WWWWWWViewController: 0x1fd9e990> modalViewController = <YYYYYViewController: 0x2089c8a0> 

El primero de ellos bloqueará la aplicación, el segundo no descartará nada y continuará mostrando el controller actual de vista presentado.

Pensamientos:

  1. los retrasos no funcionarán ya que no sabemos cuándo comenzar el retraso
  2. ¿Hay alguna forma de rastrear cuándo se completan las transiciones de vista?
  3. ¿Todos deberían ver la anulación de los controlleres? ¿Aparecerá, alertaron y alertaron la aplicación cuando es seguro descartar?
  4. tal vez en lugar de descartar, simplemente debería configurar un nuevo controller de vista raíz?
  5. Me he asegurado de que todas las vistas anuladas (will | did) (dis)? Aparezcan methods llamados super method.
  6. Cualquier solución que requiera que todos los controlleres de vista anulen la vista (did | will) aparecerán methods para rastrear los sonidos de estado, ya que podrían causar problemas si olvidamos establecer la class base para un nuevo controller de vista.

Haz algo como esto. Prueba esto una vez,

 UIViewController *controller = self.presentingViewController; //THIS LINE IS IMP [self dismissViewControllerAnimated:YES completion:^{ [controller presentViewController:adminViewController animated:YES completion:nil]; adminViewController.view.superview.frame = CGRectMake(1024/2 - 400, 768/2 - 280, 800 , 560);//it's important to do this after [adminViewController release]; }]; 

Una forma que me ha funcionado es asignar un nuevo controller de vista al controller de vista raíz. De esta forma, las vistas en la antigua jerarquía pueden animar y hacer que sus corazones se contenten mientras tenemos nuevos controlleres.

p.ej

 - (void)restartSession { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil]; ConnectingToServerViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"ConnectingToServerViewController"]; vc.modalPresentationStyle = UIModalPresentationFullScreen; [UIApplication shanetworkingApplication].delegate.window.rootViewController = vc; } 

No estoy seguro si soy consciente de todas las desventajas de esto. ¿Quizás los controlleres de vista antiguos nunca se liberen debido a una reference fuerte y colgando? Ya no estamos reutilizando ConnectingToServerViewController, tenemos que volver a crear eso cada vez.

Basé el código en lo que vi en esta respuesta para administrar y descartar varios controlleres de vista en iOS .

Parece que está intentando descartar el controller de vista cuando no se encuentra actualmente en la pantalla. Para verificar si está en la pantalla puedes usar:

 if (self.presentedViewController.view.window) { [self dismissViewControllerAnimated:NO completion:nil]; } else { self.presentedViewController = nil; } 

Responderé en order.

¿Hay alguna forma de rastrear cuándo se completan las transiciones de vista?

Puedes intentar con UINavigationControllerDelegate (si estás usando uno de esos). Otro enfoque podría ser el uso de un animador personalizado.

¿Todos deberían ver la anulación de los controlleres? ¿Aparecerá, alertaron y alertaron la aplicación cuando es seguro descartar?

Eso es una opción. Eres libre de hacerlo si quieres. Otra opción es no hacer eso. Creo que los controlleres de vista de contenedor como el controller de navigation tienen mejores enfoques.

Debería configurar un nuevo controller de vista raíz?

Yo sugeriría hacer lo contrario. Yo establecería SignInViewController / MainAppViewController como el flujo raíz, y presentaré modally ConnectingToServerViewController bajo demanda. En mi opinión, ese es un enfoque más saludable.

Espero eso ayude.