【发布时间】:2019-08-25 19:04:50
【问题描述】:
我想对 Swift 中的方法调度有一个深入的了解。我从this popular blog 读到以下三种类型的调度:
- 动态
- 表(Swift 中的见证表)
- 留言
在该博客中,作者说 NSObject 子类型维护一个调度表(见证表)以及一个消息调度层次结构。 作者分享的sn-p代码如下:
class Person: NSObject {
func sayHi() {
print("Hello")
}
}
func greetings(person: Person) {
person.sayHi()
}
greetings(person: Person()) // prints 'Hello'
class MisunderstoodPerson: Person {}
extension MisunderstoodPerson {
override func sayHi() {
print("No one gets me.")
}
}
greetings(person: MisunderstoodPerson()) // prints 'Hello'
我将引用作者对在 Person 实例上调用 sayHi() 的推理:
greetings(person:) 方法使用表调度来调用 sayHi()。 这会按预期解决,并打印“Hello”。也没什么 这里令人兴奋。现在,让我们继承 Person 类
作者继续解释了在 MisunderstoodPerson 类型转换为 Person 的实例上的调用 sayHi():
注意 sayHi() 是在扩展中声明的,这意味着 方法将通过消息调度调用。问候时(人:) 被调用,sayHi() 通过表被分派给 Person 对象 派遣。由于 MisunderstoodPerson 覆盖是通过消息添加的 调度,MisunderstoodPerson 的调度表仍然有 调度表中的人员实现,随之而来的是混乱。
想知道作者是如何得出的结论greetings(person:)方法使用表dispatch调用sayHi()
作者在博客前面提到的一件事是,当 NSObject 子类在初始声明中声明方法时(意味着不在扩展中),将使用表调度。
所以我假设 greetings(person:) 方法的参数 'person' 类型是 Person 并且调用的方法是 sayHi() ,它在Person 类的初始声明使用了一个表调度,并调用了来自 Person 的 sayHi()。 可以肯定地说使用了 Person 见证表。
一旦我们有了 MisunderstoodPerson 的子类并将这个实例传递给 greetings(person:),这个实例应该被视为 Person。 我在这里感到困惑,并在这里有几个问题。
- 实例属于 MisunderstoodPerson 类型,因此会见证 MisunderstoodPerson 表在此处使用。
- 或者该实例已被类型转换为 Person,因此此处将使用 Person 的见证表。
作者没有在博客中说明应该使用谁的见证表。即使在某些情况下,我也觉得作者甚至描述了为协议创建见证表的编译器。从他在博客中分享的图片中可以明显看出,如下所示。
【问题讨论】: