Возможна ли статическая диспетчеризация для методов класса в Swift?

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

Ответ

Да, возможна. Статическая (прямая) диспетчеризация определяется на этапе компиляции и происходит быстрее динамической. Для методов класса она применяется в следующих случаях:

  1. static методы и свойства: Принадлежат самому типу, а не его экземплярам. Не могут быть переопределены.
  2. final методы и свойства: Помеченные как final в классе не могут быть переопределены в подклассах, что позволяет компилятору использовать статическую диспетчеризацию.
  3. private и fileprivate методы: Если метод не виден за пределами файла или типа, компилятор гарантирует отсутствие переопределения и может оптимизировать вызов.
  4. Методы, вызываемые на типе Self, известном на момент компиляции: Когда нет полиморфизма.

Пример:

class Vehicle {
    static func describeClass() { print("Это Vehicle") } // Статическая диспетчеризация
    final func startEngine() { print("Двигатель запущен") } // Статическая диспетчеризация
    func honk() { print("Beep!") } // Потенциально динамическая (если переопределить)
}

class Car: Vehicle {
    // override func startEngine() { } // Ошибка: метод 'final'
    override func honk() { print("Honk!") } // Динамическая диспетчеризация
}

let myCar: Vehicle = Car()
myCar.startEngine() // Вызовется напрямую метод Vehicle.startEngine (статически)
myCar.honk()       // Вызовется метод Car.honk через таблицу диспетчеризации (динамически)
Vehicle.describeClass() // Статический вызов

Почему это важно? Статическая диспетчеризация исключает накладные расходы на поиск реализации в таблице виртуальных методов (vtable), что повышает производительность. Использование final и static там, где это допустимо по дизайну, — хорошая практика для оптимизации.