Диспетчеризация: решает то, где метод объявлен 👻
⚡️ Какой механизм вызова вы получите, определяется тем, где метод объявлен, а не тем, как вы его вызываете. Статически: структуры и энумы при вызове по конкретному типу, final-классы и final-методы, и всё, что объявлено в extension. Через таблицу: не-final методы классов (vtable), требования протокола (witness table), @objc dynamic(objc_msgSend).
⚠️ Главная ловушка — протокольные расширения. Метод, который входит в требования протокола, диспетчеризуется через witness table, и реализация конформящего типа побеждает. Метод, объявленный только в extension и не входящий в требования, резолвится статически по статическому типу — и версия из расширения выиграет, даже если конкретный тип определил свою. SE-0164 прямым текстом: «функции в протокольных расширениях нельзя переопределить, они всегда используют прямую диспетчеризацию». Важно, что это про статический тип: ловушка срабатывает и через any P, и через дженерик <T: P>.
⚠️ Ещё две поправки. «Value-типы всегда статические» — неверно: структура, витнессящая требование, при вызове через any P или неспециализированный дженерик идёт через witness table. И @objc сам по себе message dispatch не даёт — нужен @objc dynamic; голый @objc лишь разрешает override.
💡 И про производительность честно, из WWDC 416: «сама по себе динамическая диспетчеризация не намного дороже статической… но она блокирует видимость для компилятора». Цена не в косвенном вызове, а в потерянных оптимизациях.
#Swift #SwiftPerformance #AdvancedSwift #iOSDevelopment #MethodDispatch