Skip to content

Explore Method Dispatch in Swift

Published: at 10:12 AM

Introduction

Method dispatch is an algorithm used to select the appropriate method that needs to be invoked upon a call. The primary goal of method dispatch is to provide the program with information on where it can find the executable code for a specific method in memory.

Table of contents

Open Table of contents

Types of Method Dispatch

Compiled languages have three types of method dispatch:

Static Dispatch

Static dispatch is the fastest dispatch method in Swift. Since there is no method overriding available, there is only one implementation of the method, and it resides at a single location in memory.

We can use static dispatch using keywords such as static ,final, private.

Static dispatch is a default method dispatch for the value types since the value types can’t be overridden.

Let’s look at some examples:

Final Keyword

Once we add the final keyword to a class, its methods do not support overriding, and this is when static dispatch comes into play.

// MARK: Final class
final class ClassExample {
    // MARK: Static dispatch
    func method() {
        // implementation ...
    }
}

Protocol Extension

Once you add a default implementation of a protocol using an extension, its dispatch method switches to static dispatch instead of using a Witness Table.

// MARK: Prorocol Extension
extension ProtocolExample {
    // MARK: Direct Dispatch
    func method() {
        // implementation ...
    }
}

class ClassExample2: ProtocolExample {}

let classExample2 = ClassExample2()
classExample2.method()

Class Extension

When a method is implemented in an extension, it means it can’t be overridden by subclasses. In this case, there is room for static dispatch.

// MARK: Example Class Extension
class ClassExample3 {}

extension ClassExample3 {
    // MARK: Direct Dispatch
    func method() {
        // implementation ...
    }
}

let classExample3 = ClassExample3()
classExample3.method()

Access Control

We can’t access a private method outside of the class body. This means that the method can’t be overridden and uses static dispatch.

// MARK: Access Control
class ClassExample4 {
    // MARK: Direct Dispatch
    private func method() {
        // implementation ...
    }
}

Table Dispatch

Table dispatch is used when we have to deal with inheritance. This is a default type of dispatch used in Swift.

Virtual Table

For each instance of a class or subclass, a virtual table is created that contains information about implemented methods for each class and stores a reference to the appropriate implementation. The main disadvantage of virtual table dispatch is that it has lower speed than static dispatch.

Let’s look at example:

// MARK: Virtual Table
class ParentClass {
    func method1() {}
    func methdod2() {}
}

class ChildClass: ParentClass {
    override func method1() {}
    func method3() {}
}

For each instance, its own virtual table is created as follows:

Virtual Table

Witness Table

A Witness Table is used by protocols and is created for each class that conforms to the protocol. The CPU uses this table to determine where it should look for an appropriate implementation. Each type (value and reference) that conforms to a protocol has its own Protocol Witness Table, which contains pointers to the methods of the type required by the protocol.

Let’s look at example:

// MARK: Witness Table Dispatch
protocol ProtocolExample {
    func method1()
    func method2()
}

class ClassExample1: ProtocolExample {
    func method1() {}
    func method2() {}
}

class ClassExample2: ProtocolExample {
    func method1() {}
    func method2() {}
}

In this case, a witness table is created for each class:

Witness Table

Message Dispatch

Message Dispatch is the most dynamic method dispatch style. It looks for an appropriate implementation during runtime. Because it operates during runtime, we can use Method Swizzling to change method implementations.

If you want to use message dispatch, you need to add @objc dynamic before a method implementation.

// MARK: Message Dispatch
class ClassExample: NSObject {
    @objc dynamic
    func method() {}
}

class SubClassExample: ClassExample {
    @objc dynamic
    override func method() {}
}

let subclass = SubClassExample()
subclass.method()

The implementation of the method is searched for within SubClassExample. If there is no implementation of this method in that class, the search continues in the parent class, and so on until it reaches NSObject.

Message Dispatch

Let’s combine all the types into a single table:

Method Dispatch

Conclusion

In summary, method dispatch in Swift is a critical aspect of code execution, impacting performance and flexibility. By choosing the right dispatch method, developers can optimize their code, ensure adaptability, and leverage Swift’s dynamic features effectively. Understanding and mastering method dispatch is essential for building efficient and adaptable Swift applications.

Thanks for reading

If you enjoyed this post, be sure to follow me on Twitter to keep up with the new content.


avatar

Nikita Vasilev

A software engineer with over 7 years of experience in the industry. Writes this blog and builds open source frameworks.


Previous Post
Understanding any and some keywords in Swift
Next Post
Responder Chain, Gesture Recognizers, Hit Testing, Main Event Loop