Ответ 1
Короче говоря, есть динамический и статический типы диспетчеризации вызовов методов.
-
Статический - адрес вызываемой функции определяется во время компиляции, поэтому затраты на такой вызов аналогичны вызову C-функции. Этот механизм используется для
private
методов или диспетчеризации вызовов методовfinal
классов. -
Динамическая диспетчеризация - это механизм, который позволяет реализовать концепцию полиморфизма ООП - адрес вызываемой функции определяется во время выполнения. У Swift есть два подтипа:
2.1. Obj-C - вы уже описали в вопросе. Этот механизм используется, когда объект наследуется от NSObject или вызывающий метод имеет префикс @objc.
2.2. На основе виртуальной таблицы (как в C++) - есть похожие таблицы-свидетели. Во время диспетчеризации вызова метода он выполняет только одну арифметическую операцию - вычисление фактического адреса функции на основе смещения функции в таблице-свидетеле базового класса и расположения таблицы-свидетеля класса объекта. Так что относительно дешевая операция по сравнению с Obj-C. Это объясняет, почему "чистый" Swift приближается к производительности C++.
Если вы не помечаете свой метод с помощью private
ключевого слова или ваш класс не является final
и в то же время ваш класс является "чистым" Swift (он не наследует NSObject), тогда используется этот механизм на основе виртуальной таблицы. Это означает, что все методы по умолчанию являются virtual
.
PS Полезная ссылка для подтверждения моего видения относительно "Типов":
https://developer.apple.com/swift/blog/?id=27
Объяснение "подтипов" основано на моем понимании.