Custom Storyboard Segue works in simulator, but not on device

I keep getting the error:

*** 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.'

      


When trying to navigate to a new view controller. Below are the controllers of the toggle switch view:

image

Even when I try to put the name of my transient class in the Segue class, it still gives an error on my device, but works fine in the simulator.

Code for the transition class:

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 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() {
    //
}

}

      

Is there anything I can't see? Or how can I get this to work?

+3


source to share


1 answer


Typically, this error indicates that you are trying to push the sega and the view controller is not being managed UINavigationController

. A simple solution usually is to inject a view controller (ie from) into a navigation controller as specified in the NSGenericException 'reason: "Push segues can only be used when controlling the original controller with a UINavigationController instance .

But since you have applied your own class UIStoryboardSegue

, I suspect that you are not trying to just use the default push segue animation. Not knowing how you control transitioningDelegate

yours, I am assuming that you need to actually override perform()

in order to expose your view controller and not push it:



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

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

      

+2


source







All Articles