Всегда ли для методов value type в Swift используется статическая диспетчеризация?

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

Ответ

Нет. Хотя для прямых вызовов методов структуры или перечисления компилятор обычно использует статическую диспетчеризацию (прямой вызов по известному адресу в compile-time), есть случаи применения динамической диспетчеризации.

Когда используется динамическая диспетчеризация:

  1. При работе через протокол (Protocol Witness Table - PWT): Когда экземпляр value type приводится к типу протокола.
  2. При использовании модификатора @objc: Если метод помечен @objc (например, для совместимости с KVO или Objective-C runtime).
  3. При использовании ключевого слова dynamic: Явное указание на необходимость динамической диспетчеризации.

Пример динамической диспетчеризации через протокол:

protocol Renderable {
    func render()
}

struct Button: Renderable {
    // Статическая диспетчеризация при прямом вызове: `Button().render()`
    // Динамическая диспетчеризация при вызове через протокол
    func render() { print("Rendering button") }
}

let renderableItem: Renderable = Button() // Тип — existential контейнер
renderableItem.render() // Диспетчеризация через Protocol Witness Table (PWT)

Итог: Статическая диспетчеризация — это оптимизация по умолчанию для value types, но семантика протоколов и взаимодействие с Objective-C runtime могут переключить ее на динамическую.