在子类扩展中,Swift派发重写的方法

扩展中的重写方法签名在某些情况下似乎会产生不可预知的结果。 下面的例子演示了两个不同的结果和一个相似的模式。

class A: UIViewController { func doThing() { print("dothing super class") } override func viewDidLoad() { print("viewdidload superclass") super.viewDidLoad() } } class B: A { } extension B { override func doThing() { print("dothing sub class") super.doThing() } override func viewDidLoad() { print("viewdidload subclass") super.viewDidLoad() } } let a: A = B() a.doThing() let vc: UIViewController = B() vc.viewDidLoad() 

这打印:

 dothing super class viewdidload subclass viewdidload superclass 

你可以看到,当它被转换为A时,它跳过了BdoThing实现, doThing当包含UIViewController时,包含了viewDidLoad两个实现。 这是预期的行为? 如果是这样,这是什么原因?

ENV:Xcode 7.3,游乐场

这里的惊喜是,编译器允许在扩展中覆盖。 这不会编译:

 class A { func doThing() { print("dothing super class") } } class B: A { } extension B { override func doThing() { // error: declarations in extensions cannot override yet print("dothing sub class") super.doThing() } } 

在你的例子中,似乎编译器给你一个通过,因为A派生自NSObject – 大概是为了让这个类与Objective-C交互。 这确实编译:

 class A : NSObject { func doThing() { print("dothing super class") } } class B: A { } extension B { override func doThing() { print("dothing sub class") super.doThing() } } 

我的猜测是,你被允许这样做的事实本身可能是一个错误。 文档说:

扩展可以向types添加新的function,但是它们不能覆盖现有的function。

而重写无处被列为扩展可以做的事情之一。 所以这似乎应该编译。 但是,也许这是为了与Objective-C兼容而被允许的,正如我之前所说的那样。 无论哪种方式,我们正在探索一个边缘案例,你已经非常好地引起了它的急躁。

特别是,前面的代码仍然不会导致dynamic调度运行。 这就是为什么你必须声明doThingdoThing那样是dynamic ,或者把它放在实际的类中,而不是扩展名 – 如果你想要多态性的话。 因此,这可以按照您的预期进行:

 class A : NSObject { dynamic func doThing() { print("dothing super class") } } class B: A { } extension B { override func doThing() { print("dothing sub class") super.doThing() } } 

这样做也是这样的:

 class A : NSObject { func doThing() { print("dothing super class") } } class B: A { override func doThing() { print("dothing sub class") super.doThing() } } 

我的结论是:非常好的例子; 提交给苹果作为一个可能的错误; 不要这样做。 在课堂上压倒一切,而不是延长。