Ответ
Диспетчеризация — это механизм выбора конкретной реализации метода для вызова. В Swift представлены следующие типы (от самого быстрого к самому медленному):
-
Статическая (Static Dispatch)
- Решение принимается на этапе компиляции.
- Используется для: обычных функций,
struct/enumметодов,finalметодов и классов,privateметодов. - Пример:
struct Calculator { func add(_ a: Int, _ b: Int) -> Int { a + b } // Статическая диспетчеризация }
-
Диспетчеризация через таблицу свидетельств (Protocol Witness Table Dispatch)
- Используется для методов протоколов и обобщенных (
generic) контекстов. - Реализация выбирается в runtime на основе конкретного типа, соответствующего протоколу.
- Пример:
protocol Drawable { func draw() } struct Circle: Drawable { func draw() { print("Drawing circle") } } let shape: Drawable = Circle() shape.draw() // Вызов через PWT
- Используется для методов протоколов и обобщенных (
-
Динамическая диспетчеризация (Virtual Table Dispatch)
- Классический ООП-подход для нефинальных (
non-final) классов. - Решение принимается в runtime на основе типа объекта.
- Пример:
class Animal { func makeSound() { print("...") } } class Dog: Animal { override func makeSound() { print("Woof!") } } let pet: Animal = Dog() pet.makeSound() // Вызов через v-table -> "Woof!"
- Классический ООП-подход для нефинальных (
-
Диспетчеризация сообщений (Objective-C Message Dispatch)
- Полностью динамическая, используется только для элементов, помеченных
@objcиdynamic. - Позволяет делать method swizzling и отвечает на
responds(to:). - Пример:
class ObjCClass: NSObject { @objc dynamic func message() { print("Dynamic message") } }
- Полностью динамическая, используется только для элементов, помеченных
Ответ 18+ 🔞
А, слушай, про диспетчеризацию в Swift, да? Ну это, блядь, такая тема, где компилятор решает, какую конкретно функцию ему запулить, когда ты пишешь someObject.someMethod(). И вариантов этих, как собак нерезаных, целых четыре, от быстрого как хуй с горы до медленного, как черепаха в соплях.
Начнём с самого шустрого, чтоб мозги не закипели сразу.
1. Статическая (Static Dispatch)
Это когда всё решается ещё на берегу, то есть на этапе компиляции. Компилятор смотрит на код, видит точный тип и говорит: «А, так это же функция add у структуры Calculator! Понял, принял, впендюрю вызов прямо сюда, нахуй». Никаких сюрпризов в рантайме. Используется для всего простого и прямолинейного: обычные функции, методы структур и энумов, final методы в классах (которые переопределить нельзя, пидарасам), private методы. Всё ясно, как божий день.
struct Calculator {
func add(_ a: Int, _ b: Int) -> Int { a + b } // Вот тут компилятор уже всё порешил. Статика, детка.
}
2. Диспетчеризация через таблицу свидетельств (Protocol Witness Table, PWT)
А вот тут уже начинается магия, но ещё не полный пиздец. Когда ты работаешь с протоколами или дженериками, компилятор заранее не знает, какой конкретно тип приползёт. «О, Drawable? — думает он. — Ну окей, у меня для каждого типа, который подписан на этот протокол, есть своя маленькая табличка (witness table), где записано, какой у него draw вызывать». Решение принимается в рантайме, но оно всё ещё быстрое и предсказуемое, потому что табличка-то уже готова.
protocol Drawable { func draw() }
struct Circle: Drawable { func draw() { print("Рисую кружочек") } }
let shape: Drawable = Circle()
shape.draw() // Рантайм смотрит в табличку для Circle и — опа! — вызывает правильный draw.
3. Динамическая диспетчеризация (Virtual Table, v-table)
Классика жанра, ебать его в сраку! Старый добрый ООП-подход из Java и C++. Для нефинальных классов. У каждого класса есть своя виртуальная таблица — список указателей на его методы. Когда ты вызываешь pet.makeSound(), система бежит смотреть: «Так, объект у нас типа Dog? Ага. Значит, в таблице для Dog ищем makeSound. Нашёл! Вот этот указатель, нахуй!». Решение тоже в рантайме, но чуть тяжеловеснее, чем PWT, потому что иерархии наследования могут быть, блядь, овердохуища.
class Animal { func makeSound() { print("...") } }
class Dog: Animal { override func makeSound() { print("Гав-гав!") } }
let pet: Animal = Dog()
pet.makeSound() // V-Table говорит: «Да это же собака! Гавкать!»
4. Диспетчеризация сообщений (Objective-C Message Dispatch)
А это, сука, полный дикий запад, наследие Objective-C. Медленнее всех, но даёт такую гибкость, что мама не горюй. Используется ТОЛЬКО для методов, помеченных @objc dynamic. Тут система не ищет в таблицах, а в рантайме сла́вит в объект сообщение: «Эй, чувак, у тебя есть метод message?». Объект может сказать «Ага, есть, держи!», а может и промолчать. Позволяет делать такие трюки, как подмена методов (method swizzling) на лету. Мощно, но дорого.
class ObjCClass: NSObject {
@objc dynamic func message() { print("Динамическое сообщение, ёпта") } // Полная дичь, полёт в космос.
}
Вот и весь расклад, блядь. От «всё ясно как дважды два» до «чё происходит, я в ахуе». Выбирай, что по душе, но помни: чем статичнее, тем быстрее.