El método UIViewControllerTransitioningDelegate no se llama en iOS 7

He creado una animation de transición personalizada para un controller de vista modal implementando los methods en el protocolo UIViewControllerTransitioningDelegate .

En iOS 8 y 9 los methods se llaman normalmente y la transición funciona. Sin embargo, en iOS 7, la animationControllerForPresentedController:presentingController:sourceController: método nunca se llama. El método animationControllerForDismissedController: todavía se llama normalmente.

 #import "MyModalTransitioningDelegate.h" #import "MyModalFadeTransition.h" @implementation MyModalTransitioningDelegate - (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { return [[MyModalFadeTransition alloc] init]; } - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed { return [[MyModalFadeTransition alloc] init]; } @end 

En el controller de vista modal (es decir, el "controller presentado") tengo lo siguiente en su método -viewDidLoad :

 self.modalTransitionDelegate = [[OTModalTransitioningDelegate alloc] init]; // This is a custom strong private property due to `tranisitioningDelegate` being a weak property. self.transitioningDelegate = self.modalTransitionDelegate; self.modalPresentationStyle = UIModalPresentationCustom; 

Establecer modalPresentationStyle no parece hacer ninguna diferencia en ninguna versión de iOS. El método que no se llama dice que está disponible en iOS 7, por lo que no estoy seguro de por qué no se llama.

El controller de vista modal se presenta con el siguiente código en el controller de vista de presentación:

 [self presentViewController:self.modalViewController animated:YES completion:nil]; 

Si alguien encuentra esto en años posteriores y está utilizando Swift 3, asegúrese de que su llamada no sea " animationControllerForPresentedController ".

A partir de Xcode 8.1, el comstackdor no reconoce automáticamente este problema y, por lo tanto, no ofrece convertir el código a la syntax moderna.

El código anterior se comstackrá pero no será una implementación de protocolo. Será simplemente una function personalizada y no calificada. (Tales son los peligros de los methods de protocolo opcionales y los innumerables problemas con el autocompletado de Xcode).

Por lo tanto, asegúrese de implementar el protocolo con la syntax de Swift 3:

 func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { // ... return your cached controller object here. } 

Y recuerde configurar el estilo de presentación en el controller de vista que se presentará:

 self.modalPresentationStyle = .custom 

Y el delegado:

 self.transitioningDelegate = self // or wherever 

Establecer la transitioningDelegate en el inicializador del controller de vista de presentación en lugar del método viewDidLoad solucionó el problema.

Aparece en iOS 7 la lógica de transición de un controller de vista se viewDidLoad antes de viewDidLoad , pero es al revés desde iOS 8 en adelante.

Otro problema es que la transitioningDelegate es una propiedad débil . Entonces puede asignársela, luego liberar su class delegada de transición antes de que la transición tenga la oportunidad de ejecutarse. Cuando se ejecuta la transición, el valor de la transitioningDelegate es nil , y sus methods nunca son llamados.

Para ver esto, haga lo siguiente:

 let myVC = UIViewController(nibName: nil, bundle: nil) likesVC.transitioningDelegate = BackgroundFadesInPresentationDelegate(viewController: likesVC) likesVC.modalPresentationStyle = .custom present(likesVC, animated: true, completion: nil) 

Luego, en su class de delegado de transición, agregue

 deinit { print("deinit") } 

Y vea si esa statement de printing se golpea antes de la transición.

Se encontrará con este problema si usa una class independiente para implementar UIViewControllerTransitioningDelegate . Esta es la razón por la cual tutoriales como este generalmente tienen implementado el delegado de transición en la class controller de vista en sí o como una extensión. Otras cosas evitan que el controller de vista se publique.

En general, en Cocoa Touch, cualquier cosa llamada "… Delegado" será una propiedad débil, para ayudar a evitar los ciclos de retención. Debería hacer sus propias properties de delegado de class personalizadas débiles también. Hay una buena sección sobre esto en las competencias de Cocoa Core de Apple.