Как комбинация модификаторов @objc и final влияет на диспетчеризацию методов?

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

Ответ

Комбинация @objc final создаёт гибридный механизм диспетчеризации, оптимизированный для взаимодействия Swift и Objective-C.

Разбор по модификаторам:

  • final — запрещает переопределение метода в подклассах. Для компилятора Swift это сигнал использовать статическую (прямую) диспетчеризацию. Вызов метода происходит напрямую по известному адресу в памяти, без поиска в таблице виртуальных функций (vtable), что даёт прирост производительности.

  • @objc — делает метод видимым для Objective-C runtime. Для этого он добавляется в Objective-C runtime таблицу диспетчеризации, что подразумевает возможность динамической диспетчеризации при вызове из Objective-C кода или через механизмы вроде #selector.

Итоговое поведение:

  1. В Swift-коде: Вызов метода будет происходить через статическую диспетчеризацию (благодаря final), что максимально эффективно.
  2. В Objective-C коде или через селекторы: Вызов будет происходить через динамическую диспетчеризацию Objective-C runtime (благодаря @objc).

Пример:

@objc final class NetworkService: NSObject {
    @objc final func sendRequest() {
        // Реализация метода
    }
}

let service = NetworkService()

// Вызов из Swift — СТАТИЧЕСКАЯ диспетчеризация (быстро)
service.sendRequest()

// Вызов через селектор — ДИНАМИЧЕСКАЯ диспетчеризация через Objective-C
let selector = #selector(NetworkService.sendRequest)
service.perform(selector)

Когда это полезно: При создании Swift-классов, которые должны быть:

  • Эффективными внутри Swift-кода (статическая диспетчеризация).
  • Доступными для KVO, таргет-экшнов (#selector), или вызовов из legacy Objective-C кода (динамическая диспетчеризация).