2

I want a protocol to inherit from an Apple protocol UIViewControllerTransitioningDelegate, add additional protocol requirements and provide a default implementation for some methods in that protocol. When I do that, the methods do not get called. When I implement the methods in the class itself, the methods do get called.

Here's what I'm talking about:

class FirstViewController: UIViewController, SlideDismissor {
    let transition: PercentDrivenInteractiveTransitionWithState? = PercentDrivenInteractiveTransitionWithState()
}

protocol SlideDismissor: UIViewControllerTransitioningDelegate {
    var transition: PercentDrivenInteractiveTransitionWithState? { get }
}

extension SlideDismissor {
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return nil // I do return something here, but for this example it isn't necessary
    }

    func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        return transition
    }
}

If I add the following code the functions do get called.

extension FirstViewController: UIViewControllerTransitioningDelegate {

    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return nil // I do return something here, but for this example it isn't necessary
    }

    func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        return transition
    }

}

These methods I'm trying to provide a default implementation for are optional methods.

Willeke
  • 14,578
  • 4
  • 19
  • 47
SirRupertIII
  • 12,324
  • 20
  • 72
  • 121
  • I also experienced the same thing trying to provide default implementation for `UIViewControllerTransitioningDelegate` – Mingming Sep 08 '16 at 07:27

2 Answers2

2

The better solution for these kinds of problems is to use composition rather than inheritance. Rather than conform to SlideDismissor, delegate to one.

(I haven't tested this code or even made sure it compiles, but this is the basic approach I would explore.)

class FirstViewController: UIViewController {

    // Rather than handle your own transitioning, delegate it to another, reusable, object.    
    override func viewDidLoad() {
        // Your original protocol suggested that the view controller wanted
        // to control what kind of transition was used, so we pass it as a paramater.
        transitioningDelegate = SlideDismissor(transition: PercentDrivenInteractiveTransitionWithState())
    }
}

// In that object, implement all the delegate methods
class SlideDismissor: NSObject, UIViewControllerTransitioningDelegate {
    let transition: PercentDrivenInteractiveTransitionWithState?

    init(transition: PercentDrivenInteractiveTransitionWithState?) {
        self.transition = transition
    }

    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return nil // I do return something here, but for this example it isn't necessary
    }

    func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        return transition
    }
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
1

I had the same issue trying to do something similar. Apparently a current limitation of protocol extensions seems to be that we can't provide default implementations of Objective-C protocols. Thus, any protocol declared in UIKit would fall under this category. This is also stated the the following recommended article about protocol-oriented programming. this is valid as of september 2016. I feel your pain =( but I guess for now this cleaner extension approach is not really feasible for the time being

Robertibiris
  • 844
  • 8
  • 15