扩展UIViewControllerAnimatedTransitioning时出现分段错误

时间:2016-01-11 23:16:48

标签: ios swift generics ios-animations

我试图使用Swift协议提供UIViewControllerAnimatedTransitioning的通用实现,但每当我有一个符合协议的对象时,我都会收到错误:

Command failed due to signal: Segmentation fault: 11

当删除泛型时,我仍然遇到问题。

这是我的协议,泛型注释掉了:

protocol TransitionControllerType: UIViewControllerAnimatedTransitioning {
//    typealias PresentingViewController: UIViewController
//    typealias PresentedViewController: UIViewController

    var isPresentation: Bool { get set }
    var presentationTransitionDuration: NSTimeInterval { get }
    var dismissTransitionDuration: NSTimeInterval { get }

    func prepareViewControllerForPresentation(viewController: UIViewController, presentingViewController: UIViewController)
    func presentViewController(viewController: UIViewController, presentingViewController: UIViewController)
    func dismissViewController(viewController: UIViewController, presentingViewController: UIViewController)
}

PresentingViewControllerPresentedViewController将代替UIViewControllerprepareViewController(::)presentViewController(::)中的dismissViewController(::)

我在UIViewControllerAnimatedTransitioning的扩展程序中提供TransitionControllerType的实施:

extension TransitionControllerType {
    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        return isPresentation ? presentationTransitionDuration : dismissTransitionDuration
    }

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        // Ensure there is a container view
        guard let containerView = transitionContext.containerView() else {
            return
        }

        // Get the view controllers
        let (fromViewController, toViewController) = transitionContext.viewControllers()

//        // Cast the view controllers
//        guard let presentedViewController = (isPresentation ? toViewController : fromViewController) as? PresentedViewController,
//            let presentingViewController = (isPresentation ? fromViewController : toViewController) as? PresentingViewController
//        else {
//            return
//        }
        guard let presentedViewController = (isPresentation ? toViewController : fromViewController),
            let presentingViewController = (isPresentation ? fromViewController : toViewController)
        else {
            return
        }

        // Get the views from the view controllers
        let presentedView = presentedViewController.view
        let presentingView = presentingViewController.view

        // If it's a presentation, prepare the view controllers
        if isPresentation {
            prepareViewControllerForPresentation(presentedViewController, presentingViewController: presentingViewController)
            containerView.addSubview(presentedView)
        }

        UIView.animateWithDuration(
            transitionDuration(transitionContext),
            delay: 0,
            usingSpringWithDamping: isPresentation ? PresentationSpringDamping : DismissSpringDamping,
            initialSpringVelocity: isPresentation ? PresentationSpringVelocity : DismissSpringVelocity,
            options: isPresentation ? UIViewAnimationOptions.CurveEaseOut : [],
            animations: {
                if self.isPresentation {
                    self.presentViewController(presentedViewController, presentingViewController: presentingViewController)
                } else {
                    self.dismissViewController(presentedViewController, presentingViewController: presentingViewController)
                }
            },
            completion: { success in
                transitionContext.completeTransition(success)

                // !!!: We have to manually add `presentationView` due to a bug
                // http://openradar.appspot.com/radar?id=5320103646199808
                if !self.isPresentation {
                    UIApplication.sharedApplication().keyWindow?.addSubview(presentingView)
                } else {
                    UIApplication.sharedApplication().keyWindow?.addSubview(presentedView)
                }
        })
    }


    func prepareViewControllerForPresentation(viewController: UIViewController, presentingViewController: UIViewController) { }
    func presentViewController(viewController: UIViewController, presentingViewController: UIViewController) { }
    func dismissViewController(viewController: UIViewController, presentingViewController: UIViewController) { }
}

此时尝试运行项目将导致成功构建。

如果我尝试在NSObject上实现协议(为了符合UIViewControllerAnimatedTransitioning),我会收到分段错误错误。

以下是我在提交transitioningDelegate时使用的AddNewMenuViewController课程,以及

使用的TransitionControllerType
class AddNewMenuTransitionControllerDelegate: NSObject, UIViewControllerTransitioningDelegate {
    func presentationControllerForPresentedViewController(presented: UIViewController, presentingViewController presenting: UIViewController, sourceViewController source: UIViewController) -> UIPresentationController? {
        return AddNewMenuPresentationController(presentedViewController: presented, presentingViewController: presenting, blurStyle: .Dark)
    }

    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return AddNewMenuTransitionController(presentation: true)
    }

    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return AddNewMenuTransitionController()
    }
}

class AddNewMenuTransitionController: NSObject, TransitionControllerType {
    var isPresentation: Bool
    var presentationTransitionDuration: NSTimeInterval = 0.3
    var dismissTransitionDuration: NSTimeInterval = 0.3

    init(presentation: Bool = false) {
        self.isPresentation = presentation

        super.init()
    }
}

为什么非泛型版本会导致与通用版本相同的分段错误?

1 个答案:

答案 0 :(得分:0)

我不认为编译器在尝试确定您的AddNewMenuTransitionController类是否满足UIViewControllerAnimatedTransitioning协议(这是您的TransitionControllerType声明所需)时,会识别通过扩展添加到TransitionControllerType协议的animateTransition的默认方法实现。

这可能对编译器有点太多要求,因为它基本上需要使用TransitionControllerType的默认实现来预构建方法列表,同时验证方法的可用性以满足其中一个要求。

如果您在TransitionControllerType的定义中不需要UIViewControllerAnimatedTransitioning,而是将其明确地添加到您的类定义中,那么这可能会起作用(但我还没有尝试过)。

我确定这不像你的目标一样干净,但是目前使用中间协议的方法的间接默认实现对于编译器来说似乎太多了。