Swift 2 Protocol Extension Does Not Call Override Method Correctly

I am having a problem using Swift 2 protocol extensions with default implementations. The basic idea is that I provided a standard implementation of the protocol method, which I override in a class that implements the protocol. This protocol extension method is called from the base class, which then calls the method that I redefined in the derived class. As a result, the overridden method is not called.

I tried to solve the problem to the smallest possible playground, which illustrates the problem below.

protocol CommonTrait: class { func commonBehavior() -> String } extension CommonTrait { func commonBehavior() -> String { return "from protocol extension" } } class CommonThing { func say() -> String { return "override this" } } class ParentClass: CommonThing, CommonTrait { override func say() -> String { return commonBehavior() } } class AnotherParentClass: CommonThing, CommonTrait { override func say() -> String { return commonBehavior() } } class ChildClass: ParentClass { override func say() -> String { return super.say() // it works if it calls `commonBehavior` here and not call `super.say()`, but I don't want to do that as there are things in the base class I don't want to have to duplicate here. } func commonBehavior() -> String { return "from child class" } } let child = ChildClass() child.say() // want to see "from child class" but it "from protocol extension" 
+8
swift swift2
source share
3 answers

Unfortunately, protocols do not have this dynamic behavior (yet).

But you can do this (using classes) by implementing commonBehavior() in ParentClass and overriding it in ChildClass . You also need CommonThing or another class to match CommonTrait , which is then the superclass of ParentClass :

 class CommonThing: CommonTrait { func say() -> String { return "override this" } } class ParentClass: CommonThing { func commonBehavior() -> String { // calling the protocol extension indirectly from the superclass return (self as CommonThing).commonBehavior() } override func say() -> String { // if called from ChildClass the overridden function gets called instead return commonBehavior() } } class AnotherParentClass: CommonThing { override func say() -> String { return commonBehavior() } } class ChildClass: ParentClass { override func say() -> String { return super.say() } // explicitly override the function override func commonBehavior() -> String { return "from child class" } } let parent = ParentClass() parentClass.say() // "from protocol extension" let child = ChildClass() child.say() // "from child class" 

Since this is just a short solution to your problem, I hope that it matches your project.

+7
source share

To simplify my lack of this, understand what the word "still" means with non-specific error. I realized that I can’t write a function with arguments to override the extended function, and the compiler gives me such an error, but if I write a simple function without arguments and make a custom implementation and call it with my overridden "simple function" This works :

 import Foundation import UIKit extension UIViewController { func slideInView(direction: Direction = Direction.LEFT, duration: CFTimeInterval = 0.5, closure:()->() ) { let animation = CABasicAnimation(keyPath: "transform.translation.x") animation.fromValue = self.view.bounds.width animation.toValue = 0 animation.duration = 0.3 animation.fillMode = kCAFillModeForwards; animation.removedOnCompletion = false UIView.animateWithDuration(0.6, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: { self.view!.layer.addAnimation(animation,forKey:nil); }, completion: {(finished) -> () in closure() }); } func slide() { self.slideInView(.LEFT,duration: 0.66) { print("Slide in Left Complete") } } } class OtherUIViewController: UIViewController { override func slide() { self.slideFromBottom(.BOTTOM,duration: 0.66) { print("Slide in Bottom Complete") } } func slideFromBottom(direction: Direction = Direction.BOTTOM, duration: CFTimeInterval = 0.5, closure:()->() ) { let animation = CABasicAnimation(keyPath: "transform.translation.y") animation.fromValue = self.view.bounds.height animation.toValue = 0 animation.duration = 0.3 animation.fillMode = kCAFillModeForwards animation.removedOnCompletion = false UIView.animateWithDuration(0.6, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: { self.view!.layer.addAnimation(animation,forKey:nil); }, completion: {(finished) -> () in closure() }); } } 
+1
source share

this is Swift behavior. It can be good or bad, depending on your needs. The quick use of static dispatch, so the method that is called must be known at compile time. There are some advantages and, as a rule, some disadvantages. To see how Swift currently works, see the following very simple example. For me it looks logical ...

 protocol P { func foo()->Void } extension P { func foo()->Void { print("protocol foo") } } class A:P { } class B:A { func foo() { print("B foo") } } class C:B { } class D: C { // here the implementation must be overriden, // due the indirect inheritance from B override func foo() { print("D foo") } } let a = A() // a is A type a.foo() // protocol foo let b = B() // B is B type b.foo() // B foo let p:P = B() // p is protocol P // compiler is not able to know, what i would like, the dynamicType of p // can be everything, conforming to protocol P p.foo() // protocol foo (p as? A)?.foo() // protocol foo // casting to B type, I decided, that p is B type (p as? B)?.foo() // B foo (p as? D)?.foo() // nothing is printed, becase the result of casting is nil // here the types are known at compile time let c = C() c.foo() // B foo let d = D() d.foo() // D foo let e:C = D() e.foo() // D foo 
+1
source share

All Articles