Ответ 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
Объяснение "подтипов" основано на моем понимании.