简体   繁体   English

UIViewControllerTransitioningDelegate 方法未在 iOS 7 中调用

[英]UIViewControllerTransitioningDelegate method not called in iOS 7

I have created a custom transition animation for a modal view controller by implementing the methods in the UIViewControllerTransitioningDelegate protocol.我通过实现UIViewControllerTransitioningDelegate协议中的方法为模态视图控制器创建了自定义过渡动画。

In iOS 8 and 9 the methods are called normally and the transition works.在 iOS 8 和 9 中,这些方法被正常调用并且转换有效。 However, in iOS 7, the animationControllerForPresentedController:presentingController:sourceController: method never gets called.然而,在 iOS 7 中, animationControllerForPresentedController:presentingController:sourceController:方法永远不会被调用。 The animationControllerForDismissedController: method still gets called normally. 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

In the modal view controller (ie the "presented controller") I have the following in its -viewDidLoad method:在模态视图控制器(即“呈现的控制器”)中,我在其-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;

Setting the modalPresentationStyle doesn't seem to make any difference in any version of iOS.设置modalPresentationStyle在任何版本的 iOS 中似乎都没有任何区别。 The method that isn't being called does say that it's available in iOS 7 so I'm not sure why it isn't being called.没有被调用的方法确实说它在 iOS 7 中可用,所以我不确定为什么它没有被调用。

The modal view controller is being presented with the following code in the presenting view controller:模态视图控制器在呈现视图控制器中呈现以下代码:

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

If anyone comes across this in later years, and you're using Swift 3, make sure that your call isn't to " animationControllerForPresentedController ".如果有人在以后遇到这种情况,并且您使用的是 Swift 3,请确保您的调用不是animationControllerForPresentedController ”。

As of Xcode 8.1, the compiler doesn't automatically recognize this problem and thus doesn't offer to convert the code to modern syntax.从 Xcode 8.1 开始,编译器不会自动识别此问题,因此不会提供将代码转换为现代语法的功能。

The above code will compile but it won't be a protocol implementation.上面的代码会编译,但它不会是协议实现。 It will just be a custom , uncalled function.它只是一个自定义的、未调用的函数。 (Such are the hazards of optional protocol methods, and the myriad problems with Xcode's autocomplete.) (这就是可选协议方法的危害,以及 Xcode 自动完成的无数问题。)

So, make sure you implement the protocol with Swift 3 syntax:因此,请确保使用 Swift 3 语法实现协议:

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

And remember to set the presentation style on the View Controller to be presented:并记得在要呈现的 View Controller 上设置呈现样式:

self.modalPresentationStyle = .custom

And the delegate:和代表:

self.transitioningDelegate = self // or wherever

Another issue is that transitioningDelegate is a weak property .另一个问题是transitioningDelegate是一个弱属性 So you can assign to it, then have your transitioning delegate class be released before the transition has a chance to run.所以你可以分配给它,然后在转换有机会运行之前释放你的转换委托类。 When the transition does run, the value of transitioningDelegate is nil , and your methods never get called.当过渡运行,值transitioningDelegatenil ,你的方法永远不会被调用。

To see this, do the following:要查看这一点,请执行以下操作:

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

Then in your transition delegate class, add然后在您的过渡委托类中,添加

deinit {
    print("deinit")
}

And see if that print statement is hit before the transition.并查看是否在转换之前命中该打印语句。

You will run into this problem if you use a freestanding class to implement the UIViewControllerTransitioningDelegate .如果您使用独立类来实现UIViewControllerTransitioningDelegate则会遇到此问题。 This is why tutorials such as this one generally have you implement the transitioning delegate in the either in the view controller class itself or as an extension.这就是为什么像这样的教程通常让您在视图控制器类本身或作为扩展中实现转换委托。 Other things are keeping the view controller from getting released.其他事情阻止视图控制器被释放。

In general in Cocoa Touch anything named "...Delegate" will be a weak property, to help avoid retain cycles.一般来说,在 Cocoa Touch 中,任何名为“...Delegate”的东西都将是一个弱属性,以帮助避免保留循环。 You should make your own custom class delegate properties weak as well.您也应该使自己的自定义类委托属性变弱。 There's a good section on this in Apple's Cocoa Core Competencies .在 Apple 的Cocoa Core Competencies 中有一个很好的部分。

Setting the transitioningDelegate in the presenting view controller's initialiser instead of the viewDidLoad method fixed the issue.在呈现视图控制器的初始化程序中设置transitioningDelegate而不是viewDidLoad方法解决了这个问题。

It appears in iOS 7 a view controller's transitioning logic is called before viewDidLoad , but is the other way around from iOS 8 onwards.它出现在 iOS 7 中,在viewDidLoad之前调用了视图控制器的转换逻辑,但从 iOS 8 开始则相反。

After digging, I found that my transitioningDelegate methods were not getting called because they were implemented in a protocol extension and the delegate methods must be @objc which is not supported in protocol extensions.挖掘后,我发现我的 transitioningDelegate 方法没有被调用,因为它们是在协议扩展中实现的,并且委托方法必须是协议扩展中不支持的@objc。 My resolution was to move this into the concrete class and add the @objc tag我的解决方案是将其移动到具体类中并添加 @objc 标记

    @objc func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        ...


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

 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM