iOS 7中未调用UIViewControllerTransitioningDelegate方法

4

我通过实现UIViewControllerTransitioningDelegate协议中的方法为模态视图控制器创建了自定义过渡动画。

iOS 8和9中,这些方法被正常调用并且过渡效果正常。然而,在iOS 7中,animationControllerForPresentedController:presentingController:sourceController:方法从未被调用。而animationControllerForDismissedController:方法仍然会被正常调用。

#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

在模态视图控制器(即“呈现的控制器”)中,我在其-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;

设置 modalPresentationStyle 在任何版本的 iOS 中似乎都没有任何区别。未被调用的方法确实说明它在 iOS 7 可用,所以我不确定为什么它没有被调用。

模态视图控制器是使用以下代码在呈现视图控制器中呈现的:

[self presentViewController:self.modalViewController
                   animated:YES
                 completion:nil];
4个回答

55

如果有人在以后的年份看到这篇文章,并且你正在使用Swift 3,请确保你的调用不是 "animationControllerForPresentedController"。

截至Xcode 8.1,编译器不会自动识别这个问题,因此不会提供将代码转换为现代语法的选项。

上面的代码可以编译,但它不会成为协议实现。 它只是一个自定义的、未被调用的函数。(这是可选协议方法的危险所在,以及Xcode自动完成的种种问题。)

因此,请确保使用Swift 3语法实现协议:

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

记得将要呈现的视图控制器的演示风格设置为:

self.modalPresentationStyle = .custom

并且代表:

self.transitioningDelegate = self // or wherever

2
非常感谢!为什么Xcode不建议原始方法是错误的呢? - Ronnel Davis
2
Swift 4 中有同样的问题。很好地捕捉到了。谢谢。 - Thanh Nguyen Van
刚刚将一个Swift 1项目迁移到了Swift 5。你的回答救了我一命。谢谢! - Honghao Z

14

另一个问题是 transitioningDelegate 是一个 弱引用属性。 因此,您可以将其分配给它,然后在过渡有机会运行之前使您的过渡代理类被 释放。当过渡确实运行时,transitioningDelegate 的值为nil,您的方法永远不会被调用。

要查看此内容,请执行以下操作:

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

然后在您的转换委托类中添加以下内容:

deinit {
    print("deinit")
}

在转场之前检查一下这个打印语句是否被执行。

如果你使用一个独立的类来实现 UIViewControllerTransitioningDelegate,你就会遇到这个问题。这就是为什么像这个教程通常让你在视图控制器类本身或作为扩展中实现转场代理。其他的事情阻止了视图控制器被释放。

一般来说,在Cocoa Touch 中任何以“...Delegate”命名的东西都将是弱属性,以帮助避免保留循环。你应该将自己的自定义类代理属性也设置为弱引用。Apple 的Cocoa Core Competencies 中有一个很好的章节介绍了这个。


在我的问题的第二个代码块中,你会看到我已经解决了这个问题,我有一个自定义强属性来保存对我的转换代理的引用。然而,这是可能会让其他人遇到问题的地方,所以感谢你的贡献。 :) - commscheck
我遇到了上述问题(在iOS 11中)。我的transitioningDelegate明显没有被释放,而我的modalPresentationStyle已经设置为.custom。更奇怪的是,我的委托中的“animationController”函数确实被调用了。这真是太疯狂了...有什么其他地方可以看看吗? - jbm
此外,在animationController(forPresented...)中记录表明,transitioningDelegate和modalTransitionStyle是正确的(或者至少,它们是我所期望的——即我的委托类和“4”或“.custom”)。 - jbm

4

transitioningDelegate在呈现视图控制器的初始化方法中设置,而不是在viewDidLoad方法中设置,可以解决此问题。

iOS 7中,视图控制器的转场逻辑会在viewDidLoad之前调用,但从iOS 8开始则相反。


0
经过深入挖掘,我发现我的 transitioningDelegate 方法没有被调用,因为它们是在协议扩展中实现的,而委托方法必须是 @objc 的,而协议扩展中不支持。 我的解决方法是将其移到具体类中并添加 @objc 标签。
    @objc func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        ...


    }
    
    // interaction for dismissing from  view
    @objc func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
   ...   
   }

 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接