ios - 扩展 UIViewControllerAnimatedTransitioning 时出现段错误

标签 ios swift generics ios-animations

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

Command failed due to signal: Segmentation fault: 11

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

这是我的协议(protocol),其中泛型被注释掉:

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 只是代替 prepareViewController(::) 中的 UIViewControllerpresentViewController(::)dismissViewController(::)

我在 TransitionControllerType 的扩展中提供了 UIViewControllerAnimatedTransitioning 的实现:

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 上实现协议(protocol)(为了符合 UIViewControllerAnimatedTransitioning),我会收到段错误错误。

下面是我在呈现 AddNewMenuViewController 时用于 transitioningDelegate 的类,以及

使用的 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()
    }
}

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

最佳答案

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

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

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

我确信这并不像您想要的那么干净,但是使用中间协议(protocol)的方法的间接默认实现目前对于编译器来说似乎太多了。

关于ios - 扩展 UIViewControllerAnimatedTransitioning 时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34732921/

相关文章:

iphone - 用粉笔效果画线( cocoa / cocoa 触感)?

objective-c - 在 Objective-C/C 中删除文件夹及其子文件夹

android - Android和IOS上的SDK检测

ios - 可编码的 MKPolygon?

swift - 获取通用类型 T 的名称作为 String

Swift 3 - DispatchQueue 内部函数

json - 使用 GSON 使用通用嵌套数据对象序列化响应对象

iOS 为条形码扫描仪添加提示音

c# - 将类型转换为 DBSet<>

c# - 默认(T)与 Activator.CreateInstance(T)