1

I'm working on an app that incorporates WYPopoverController and it works great in place where it should. I want to add custom animations between two controllers, instead of built in push / pop.

In navigation controller containing FROM and TO controllers I don't do anything related to the WYPopoverController, neither in controllers FROM and TO.

I've implemented navigation controller delegate, really simple and animator class that handles actual animation.

public class NavigationControllerDelegate: NSObject, UINavigationControllerDelegate {

let animator = Animator()

public func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {

    if operation == UINavigationControllerOperation.Pop {
        return self.animator
    }

    return nil
}
}

Animator class:

class Animator: NSObject, UIViewControllerAnimatedTransitioning {

public func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
    return 0.33
}

public func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!

    transitionContext.containerView().addSubview(toVC.view)
    toVC.view.alpha = 0

    UIView.animateWithDuration(self.transitionDuration(transitionContext), animations: { () -> Void in
        fromVC.view.transform = CGAffineTransformMakeScale(0.1, 0.1)
        toVC.view.alpha = 1
    }) { (finished) -> Void in
        fromVC.view.transform = CGAffineTransformIdentity
        transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
    }
}  
}

In the FROM controller I initialize navigation delegate

override public func viewDidLoad() {
    super.viewDidLoad()
    // ... some other code here
    self.navigationController?.delegate = NavigationControllerDelegate()
}

Everything compiles and runs up until the point when I tap the (collection) cell and want to move to TO controller. At that point app crashes with error: -[CALayer navigationController:animationControllerForOperation:fromViewController:toViewController:]: unrecognized selector sent to instance 0x7fc72e53e970

I've added a breakpoint and I end up inside sizzled_pushViewController:animated: method of UINavigationController. To be honest I have no idea how to approach the issue.

screen shot 2015-05-21 at 15 48 04

Marcin Zbijowski
  • 820
  • 1
  • 8
  • 23

2 Answers2

1

As it turns out, solution has nothing to do with the WYPopoverController whatsoever. Apparently setting navigation controller delegate from within its root controller is not the way it should be done. I manage to refactor my code to get rid of the aforementioned library, but it was still crashing with the very same exception.

-[CALayer navigationController:animationControllerForOperation:fromViewController:toViewController:]: unrecognized selector sent to instance 0x7fc72e53e970

At that point I was really confused. After some more digging and hair pulling I got working solution. I initialised navigation controller delegate in storyboard and all pieces fell into right place.

Marcin Zbijowski
  • 820
  • 1
  • 8
  • 23
  • Same error. And indeed, the issue is in the navigation delegate. Looks like at some moment `WYPopoverController` triggers that method and refers to the delegate. In my case I set a controller to the delegate and once it was deallocated, the delegate still kept the reference. – Mike Jul 15 '17 at 00:55
0

The WYPopoverController is using Method Swizzling to Swizzle the pushViewController:animated for the UINavigationController

So basically when you see the [self sizzled_pushViewController:aViewController animated:aAnimated]; selector being called there, it means that your pushViewController:animated selector is actually called, as the method has been swizzled.

Now regarding your crash, it seems that instead of the selector navigationController:animationControllerForOperation:fromViewController:toViewController: being sent to the UINavigationController, it is being sent to the CALayer, which of course doesn't respond to that and the app crashes.

Why this is happening I cannot guess from what I see here, but what I said, hopefully will get you on the correct track

Lefteris
  • 14,550
  • 2
  • 56
  • 95
  • yes, I know that ;) I've done my homework before posting it here and on GitHub. I have no idea why the hell it's calling CALayer when delegate is set to object of my class... – Marcin Zbijowski May 22 '15 at 07:52