Objective-C - это очень зависимый от времени выполнения язык. Что я имею в виду под этим утверждением?
Это означает, что Objective-C предоставил нам возможности, с помощью которых вы могли бы выполнять множество проверок кода и изменять реализации кода во время выполнения.
Язык обычно откладывает многие свои задачи на время выполнения, чтобы ускорить время компиляции.
Было много функций, которые это включало во время выполнения, например:
Проверка принадлежности экземпляра к определенному типу класса с помощью функции isMemberOfClass. Или, если вы хотите проверить, принадлежит ли он определенному классу в его иерархии наследования, вы можете использовать isKindOfClass.
Проверка того, может ли класс реагировать на определенный метод с помощью функции Responsestoselector
Динамическое изменение реализаций методов во время выполнения с использованием чего-то, называемого методом swizzling
Добавление реализаций методов во время выполнения с помощью class_addMethod
И их гораздо больше. Все это происходит благодаря библиотеке, называемой библиотекой времени выполнения Objective-C, встроенной в Objective-C, которую использует NSObject. Учитывая, что почти каждый класс в Objective-C должен был наследовать от этого класса, эти функции были доступны почти везде.
Теперь мы знаем, что Objective-C является очень гибким языком во время выполнения и что вы можете существенно изменять реализации методов, добавлять реализации методов и т.д., И все это во время выполнения. Это может создать проблему для способа отправки V-таблицы, поскольку генерация V-таблицы происходит во время компиляции. V-таблица, сгенерированная во время компиляции, может не представлять правильную реализацию метода, который необходимо вызвать, поскольку он мог быть удален или новые методы могли быть добавлены во время выполнения.
Отправка сообщений - это решение вышеуказанных проблем, когда во время выполнения поддерживается другая таблица. Во время фактического вызова во время выполнения в этой таблице выполняется поиск, чтобы определить фактический адрес метода для выполнения вызова.
Методы, использующие динамическую диспетчеризацию, не включаются в V-таблицу, сгенерированную во время компиляции, поскольку такие методы могут быть заменены во время выполнения из-за возможностей среды выполнения Objective-C.
Это метод отправки по умолчанию в Objective-C для всех элементов, которые необходимо динамически отправлять.
динамический и @objc
Этот раздел посвящен сгенерированному SIL коду в несколько более глубоком смысле. Единственная теория, которая может быть предложена здесь, заключается в следующем: ключевое слово dynamic используется в Swift для включения динамической отправки для методов, которым это необходимо (например, в методе swizzling или в коде, связанном с KVO), тогда как @objc используется для предоставления этого метода Objective-C.
До Swift 3 все динамические элементы автоматически предоставлялись Objective-C, но начиная с Swift 4 вы должны явно указывать как dynamic, так и @objc перед методами, которые вам нужно предоставить для динамической отправки.
В Swift методы, которые необходимо использовать в качестве объектов селектора, должны быть объявлены с помощью @objc по той причине, что эти методы все еще должны быть доступны Objective-C. Механизм целевого действия, который используется здесь, по-прежнему написан на Objective-C.
Например, когда вы добавляете наблюдателей уведомлений или методы к UIBarButton, созданному в коде (с использованием механизма целевого действия и т.д.), Эти методы используют возможности среды выполнения Obj-C для вызова этих методов.
С этого момента это будет небольшое погружение в сгенерированный SIL код, и это будет не очень красиво. Давайте возьмем пример простого класса: