0

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

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)
}

PresentingViewController并且PresentedViewController只是代替UIViewControllerin prepareViewController(::),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()
    }
}

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

4

1 回答 1

0

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

这对编译器的要求可能有点多,因为它本质上需要使用 TransitionControllerType 的默认实现预先构建方法列表,同时它正在验证其要求之一的方法的可用性。

如果您在 TransitionControllerType 的定义中不需要 UIViewControllerAnimatedTransitioning 而是将其显式添加到您的类定义中,这可能有效(但我没有尝试过)。

我确信这并不像您的目标那样干净,但是此时使用中间协议的方法的间接默认实现似乎对编译器来说太多了。

于 2016-01-12T02:09:03.517 回答