Swift 2协议扩展未正确调用重写方法

Swift 2协议扩展未正确调用重写方法,swift,swift2,Swift,Swift2,我在使用Swift 2的协议扩展和默认实现时遇到了一个问题。基本要点是,我提供了一个协议方法的默认实现,我正在实现该协议的类中重写该协议方法。该协议扩展方法是从基类调用的,然后基类调用我在派生类中重写的方法。结果是未调用重写的方法 我试图将问题提炼到尽可能小的范围内,这说明了下面的问题 protocol CommonTrait: class { func commonBehavior() -> String } extension CommonTrait { func c

我在使用Swift 2的协议扩展和默认实现时遇到了一个问题。基本要点是,我提供了一个协议方法的默认实现,我正在实现该协议的类中重写该协议方法。该协议扩展方法是从基类调用的,然后基类调用我在派生类中重写的方法。结果是未调用重写的方法

我试图将问题提炼到尽可能小的范围内,这说明了下面的问题

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's "from protocol extension”

不幸的是,协议还没有这样的动态行为

但是,您可以(在类的帮助下)通过在
ParentClass
中实现
commonBehavior()
并在
ChildClass
中重写它来实现这一点。您还需要
CommonThing
或另一个类来符合
CommonTrait
,它是
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"

由于这只是解决您问题的一个简短方法,我希望它适合您的项目。

为了简化我对“尚未”一词在非特定错误中的含义的理解。我发现,在重写扩展函数时,我似乎无法编写带参数的函数,编译器会给我这样一个错误,但如果我编写一个没有参数的简单函数,并进行自定义实现,然后使用重写的“简单函数”调用它,它就会工作:

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()
        });
    }
}

这是斯威夫特的行为。它可以是好的,也可以是坏的,这取决于你的需求。Swift使用静态分派,因此在编译期间必须知道调用哪个方法。这有一些优点,但通常也有一些缺点。要了解Swift目前的工作原理,请参见下一个非常简单的示例。对我来说,它看起来合乎逻辑

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

我建议你在这里阅读这篇文章来了解它是如何工作的:另一个更具体地解决这个问题的好方法(不是一般的。只有
ChildClass
才会有这种行为)是用
return(self-as?ChildClass)?.commonBehavior()替换
ParentClass
函数中的代码??commonBehavior()
(使用问题的代码示例)。这意味着父类需要知道它的子类,不是吗?而是破坏了封装。@Remover你说得对,超类必须知道它的子类确实破坏了封装。所以这应该只是一个例子,说明你还可以做些什么,尽管我不推荐。