Search code examples
iosuistoryboardsegue

Custom unwind segue crashing in iOS11


Update

Playing around with this I've found that if I do this from the presented controller everything works as expected:

self.dismiss(animated: true)

And the custom segue's animation is executed. However if I try to use an unwind segue like this:

self.performSegue(withIdentifier: "logoDisplayed", sender: self)

Then I get the crash mentioned below. Also I've found that the custom segue only works if I set the 'kind' to 'Present modally'. If I set it to 'Custom' then again I get the crash telling me there's no perform() even though there clearly is.

Still trying to figure this out.

Original Post

I know this has been talked about before (here, here and here)

But I've not been able to get a custom unwind segue working in iOS11. below is the custom segue I'm using. It works perfectly when I set it as the class of a model segue, but doesn't work when I set it as the class for an unwind segue. Instead the app crashes with this error:

2017-11-20 22:29:09.640934+1100 Crux[46709:6046351] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', 
reason: 'Could not perform segue with identifier 'logoDisplayed'. 
A segue must either have a performHandler or it must override -perform.'
*** First throw call stack:
(
0   CoreFoundation                      0x00000001100c012b __exceptionPreprocess + 171
1   libobjc.A.dylib                     0x000000010f06bf41 objc_exception_throw + 48
2   UIKit                               0x0000000111c1061d -[UIStoryboardSegue _prepare] + 0
3   Crux                                0x000000010dacecc8 _T04Crux13AnimatedSegueC7performyyF + 280
...

The segue's setup like this:

enter image description here

The code for my segue is this:

class FadeInAnimator: NSObject, UIViewControllerAnimatedTransitioning {

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 2.0
    }

    func animateTransition(using transitionContext:      UIViewControllerContextTransitioning) {

        let containerView = transitionContext.containerView
        let toVC = transitionContext.viewController(forKey:UITransitionContextViewControllerKey.to)

        containerView.addSubview(toVC!.view)
        toVC!.view.alpha = 0.0

        let duration = transitionDuration(using:transitionContext)
        UIView.animate(withDuration:duration,
                       animations: {
                        toVC!.view.alpha = 1.0
        },
                       completion: { finished in
                        let cancelled = transitionContext.transitionWasCancelled
                        transitionContext.completeTransition(!cancelled)
        })
    }
}

class AnimatedSegue:UIStoryboardSegue, UIViewControllerTransitioningDelegate {

    override func perform() {
        source.transitioningDelegate = self
        destination.transitioningDelegate = self
        super.perform()
    }

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return FadeInAnimator()
    }

    func animationController(forPresented presented: UIViewController,
                             presenting: UIViewController,
                             source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return FadeInAnimator()
    }
}

Anyone know where I might have gone wrong?


Solution

  • Found the problem. I had some old code sitting in the source controller:

    override func segueForUnwinding(to toViewController: UIViewController, from fromViewController: UIViewController, identifier: String?) -> UIStoryboardSegue? {
        return AnimatedSegue(identifier: identifier, source: fromViewController, destination: toViewController)
    }
    

    Which was being called and causing the problem.