Почему статическая диспетчеризация выполняется быстрее динамической?

«Почему статическая диспетчеризация выполняется быстрее динамической?» — вопрос из категории Swift Core, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Статическая диспетчеризация быстрее, потому что вызов метода разрешается на этапе компиляции, а не во время выполнения программы.

Принцип работы:

  • Компилятор точно знает, какой метод нужно вызвать, и подставляет его прямой адрес в машинный код.
  • Это исключает накладные расходы на поиск реализации метода в таблице виртуальных методов (vtable) или через механизмы Objective-C runtime.

Пример сравнения в Swift:

// Статическая диспетчеризация (значение-типы, final-классы, private методы)
struct Calculator {
    func add(_ a: Int, _ b: Int) -> Int { a + b } // Адрес метода известен при компиляции
}
let result = Calculator().add(5, 3) // Прямой вызов

// Динамическая диспетчеризация (обычные классы, полиморфизм)
class Animal {
    func makeSound() { print("Some sound") } // Реализация ищется в vtable
}
class Dog: Animal {
    override func makeSound() { print("Bark") }
}
let pet: Animal = Dog()
pet.makeSound() // Во время выполнения определяется, что нужно вызвать Dog.makeSound()

Где используется:

  • Для структур (value types) — всегда статически.
  • Для классов — если метод помечен как final, private или класс сам final.
  • Для протоколов с ограничением some или при использовании обобщённых (generic) контекстов.