方法调度是一种用于选择需要在调用时调用的适当方法的算法。方法调度的主要目标是向程序提供有关在内存中可以找到特定方法的可执行代码的信息。
编译语言有三种类型的方法调度:
静态调度是Swift中最快的调度方法。由于没有可用的方法重写,因此方法只有一个实现,并且它位于内存中的单个位置。
\ 我们可以使用诸如static、final、private等关键字来使用静态调度。
\ 静态调度是值类型的默认方法调度,因为值类型不能被重写。
\ 让我们看一些例子:
一旦我们向类添加final关键字,其方法就不支持重写,这时静态调度就会发挥作用。
// MARK: Final class final class ClassExample { // MARK: Static dispatch func method() { // implementation ... } }
一旦你使用扩展添加协议的默认实现,其调度方法就会切换到静态调度,而不是使用见证表。
// MARK: Prorocol Extension extension ProtocolExample { // MARK: Direct Dispatch func method() { // implementation ... } } class ClassExample2: ProtocolExample {} let classExample2 = ClassExample2() classExample2.method()
当方法在扩展中实现时,这意味着它不能被子类重写。在这种情况下,有静态调度的空间。
// MARK: Example Class Extension class ClassExample3 {} extension ClassExample3 { // MARK: Direct Dispatch func method() { // implementation ... } } let classExample3 = ClassExample3() classExample3.method()
我们不能在类体外访问私有方法。这意味着该方法不能被重写,并使用静态调度。
// MARK: Access Control class ClassExample4 { // MARK: Direct Dispatch private func method() { // implementation ... } }
当我们必须处理继承时,会使用表格调度。这是Swift中使用的默认调度类型。
对于类或子类的每个实例,都会创建一个虚拟表,其中包含有关每个类已实现方法的信息,并存储对适当实现的引用。虚拟表调度的主要缺点是它的速度低于静态调度。
\ 让我们看一个例子:
// MARK: Virtual Table class ParentClass { func method1() {} func methdod2() {} } class ChildClass: ParentClass { override func method1() {} func method3() {} }
\ 对于每个实例,都会创建自己的虚拟表,如下所示:
\
见证表由协议使用,并为符合协议的每个类创建。CPU使用此表来确定应该在哪里查找适当的实现。符合协议的每种类型(值和引用)都有自己的协议见证表,其中包含指向协议所需的类型方法的指针。
\ 让我们看一个例子:
// MARK: Witness Table Dispatch protocol ProtocolExample { func method1() func method2() } class ClassExample1: ProtocolExample { func method1() {} func method2() {} } class ClassExample2: ProtocolExample { func method1() {} func method2() {} }
\ 在这种情况下,为每个类创建一个见证表:
\
消息调度是最动态的方法调度风格。它在运行时寻找适当的实现。因为它在运行时操作,我们可以使用方法交换来更改方法实现。
\ 如果你想使用消息调度,你需要在方法实现前添加@objc dynamic。
// MARK: Message Dispatch class ClassExample: NSObject { @objc dynamic func method() {} } class SubClassExample: ClassExample { @objc dynamic override func method() {} } let subclass = SubClassExample() subclass.method()
\ 在SubClassExample中搜索方法的实现。如果该类中没有此方法的实现,则搜索继续在父类中进行,依此类推,直到达到NSObject。
\
让我们将所有类型合并到一个表格中:
\
总之,Swift中的方法调度是代码执行的关键方面,影响性能和灵活性。通过选择正确的调度方法,开发人员可以优化他们的代码,确保适应性,并有效地利用Swift的动态特性。理解和掌握方法调度对于构建高效和适应性强的Swift应用程序至关重要。


