ios - 自定义 Storyboard Segue 在模拟器中有效,但在设备上无效

标签 ios iphone swift segue uistoryboardsegue

我不断收到错误:

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Push segues can only be used when the source controller is managed by an instance of UINavigationController.'

尝试切换到新的 View Controller 时。下面是 segue 切换 View Controller :

image

即使我尝试将转换类的名称放入 Segue 类中,它仍然会在我的设备上给出错误,但在模拟器中运行得非常好。

过渡类的代码:

class TransitionManager: UIStoryboardSegue, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate  {

private var presenting = true

// MARK: UIViewControllerAnimatedTransitioning protocol methods

// animate a change from one viewcontroller to another
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

    // get reference to our fromView, toView and the container view that we should perform the transition in
    let container = transitionContext.containerView()
    let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
    let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!

    // set up from 2D transforms that we'll use in the animation
    let π : CGFloat = 3.14159265359

    let offScreenRight = CGAffineTransformMakeRotation(-π/2)
    let offScreenLeft = CGAffineTransformMakeRotation(π/2)

    // prepare the toView for the animation
    toView.transform = self.presenting ? offScreenRight : offScreenLeft

    // set the anchor point so that rotations happen from the top-left corner
    toView.layer.anchorPoint = CGPoint(x:0, y:0)
    fromView.layer.anchorPoint = CGPoint(x:0, y:0)

    // updating the anchor point also moves the position to we have to move the center position to the top-left to compensate
    toView.layer.position = CGPoint(x:0, y:0)
    fromView.layer.position = CGPoint(x:0, y:0)

    // add the both views to our view controller
    container.addSubview(toView)
    container.addSubview(fromView)

    // get the duration of the animation
    // DON'T just type '0.5s' -- the reason why won't make sense until the next post
    // but for now it's important to just follow this approach
    let duration = self.transitionDuration(transitionContext)

    // perform the animation!
    // for this example, just slid both fromView and toView to the left at the same time
    // meaning fromView is pushed off the screen and toView slides into view
    // we also use the block animation usingSpringWithDamping for a little bounce
    UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.8, options: nil, animations: {

        // slide fromView off either the left or right edge of the screen
        // depending if we're presenting or dismissing this view
        fromView.transform = self.presenting ? offScreenLeft : offScreenRight
        toView.transform = CGAffineTransformIdentity

        }, completion: { finished in

            // tell our transitionContext object that we've finished animating
            transitionContext.completeTransition(true)

    })

}

// return how many seconds the transiton animation will take
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
    return 0.75
}

// MARK: UIViewControllerTransitioningDelegate protocol methods

// return the animataor when presenting a viewcontroller
// remmeber that an animator (or animation controller) is any object that aheres to the UIViewControllerAnimatedTransitioning protocol
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {

    // these methods are the perfect place to set our `presenting` flag to either true or false - voila!
    self.presenting = true
    return self
}

// return the animator used when dismissing from a viewcontroller
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    self.presenting = false
    return self
}

override func perform() {
    //
}

}

有什么我想念的吗?或者我怎样才能让它发挥作用?

最佳答案

通常该错误表明您正在尝试执行推送转场,并且呈现 View Controller 不受 UINavigationController 管理。简单的解决方案通常是将呈现(即来自) View Controller 嵌入导航 Controller 中,如 NSGenericException', reason: 'Push segues can only be used when the source controller is managed by an instance of UINavigationController 中所述。 .

但由于您推出了自己的 UIStoryboardSegue 类,我怀疑您并没有尝试简单地使用默认的推送转场动画。在不知道您如何管理您的 transitioningDelegate 的情况下,我的猜测是您需要实际覆盖 perform() 来呈现您的 View Controller 而不是推送它:

override func perform() {
    let fromVC  = sourceViewController as UIViewController
    let toVC    = destinationViewController as UIViewController

    fromVC.presentViewController(toVC as UIViewController, animated: true, completion: nil)
}

关于ios - 自定义 Storyboard Segue 在模拟器中有效,但在设备上无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26254058/

相关文章:

ios - 对成员 'dataTask(with:completionHandler:)' 的模糊引用

iphone - 保存上下文中的 CoreData 错误,NSPersistentStoreCoordinator 没有持久存储

ios - 需要将方法从 Objective-C 转换为 iOS 中的 C

ios - Core-Plot 正确格式化图形

iphone - -JSONValue 失败。错误是 : Unexpected end of input

ios - 如何使用 for 循环生成按钮数组,然后使用 CADisplayLink 为它们设置动画

ios - 编码的自动布局对于 UITableView 无法正常工作

ios - 您如何支持滑动以删除具有组合布局的 UICollectionView 列表中的行?

ios - 通过委托(delegate)将数据传递给各种 View Controller

iphone - 如何准备应用程序以提交到应用程序商店?我*不断*收到代码签名错误?