Swift调度到子类扩展中的重写方法 [英] Swift dispatch to overridden methods in subclass extensions

查看:86
本文介绍了Swift调度到子类扩展中的重写方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

覆盖扩展中的方法签名似乎会产生不可预测的结果。以下示例演示了两种具有类似模式的不同结果。

overriding method signatures in extensions seems to produce unpredictable results in certain cases. The following example demonstrates two different results with a similar pattern.

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

你可以看到这跳过 B 的imp doThing 的投射,当它被转换为 A 时,但包含 viewDidLoad的两种实现 UIViewController 时code>。这是预期的行为吗?如果是这样,原因是什么?

You can see this skips the B's implementation of doThing when it is cast as A, however includes both implementations of viewDidLoad when cast as UIViewController. Is this the expected behavior? If so, what is the reason for this?

ENV:Xcode 7.3,Playground

ENV: Xcode 7.3, Playground

推荐答案

这里的惊喜是编译器允许扩展中的覆盖。此编译:

The surprise here is that the compiler permits the override in the extension. This doesn't compile:

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

在你的例子中,似乎编译器给你一个pass,因为A派生自NSObject - 可能是为了让这个类能够交互与Objective-C。这个 编译:

In your example, it appears that the compiler gives you a pass because A derives from NSObject — presumably in order to allow this class to interact with Objective-C. This does compile:

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

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

My guess is that the fact you're allowed to do this override at all is itself possibly a bug. The docs say:


扩展可以为类型添加新功能,但它们不能覆盖现有功能。

Extensions can add new functionality to a type, but they cannot override existing functionality.

并且覆盖无法列为扩展可以做的事情之一。所以看起来这应该编译。但是,正如我之前所说的那样,或许可以故意与Objective-C兼容。无论哪种方式,我们正在探索一个边缘情况,你已经很好地引出它的边缘。

And overriding is nowhere listed as one of the things an extension can do. So it seems like this should not compile. However, perhaps this is permitted deliberately for compatibility with Objective-C, as I said before. Either way, we are then exploring an edge case, and you have very nicely elicited its edginess.

特别是,前面的代码仍然不会导致动态调度变为操作。这就是为什么你必须按照@jtbandes的建议将 doThing 声明为 dynamic ,或者将它放在实际的类中而不是扩展 - 如果你想要多态运行。因此,这可以按照您的预期方式工作:

In particular, the preceding code still doesn't cause dynamic dispatch to become operational. That's why you either have to declare doThing as dynamic, as suggested by @jtbandes, or put it in the actual class rather than the extension — if you want polymorphism to operate. Thus, this works the way you expect:

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

我的结论是:非常好的例子;将其作为可能的错误提交给Apple;并且不要那样做。在课堂上重写,而不是在扩展中。

My conclusion would be: Very nice example; submit it to Apple as a possible bug; and Don't Do That. Do your overriding in the class, not in the extension.

这篇关于Swift调度到子类扩展中的重写方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆