Objective C механизм отправки сообщений

Я просто начинаю играть с Objective C (пишу игрушечные приложения для iPhone), и мне любопытно, какой механизм используется для отправки сообщений. У меня есть хорошее понимание того, как виртуальные функции в C++ обычно реализуются и каковы затраты по сравнению со статическим или не виртуальным вызовом метода, но я не знаю, как Obj-C знать, как отправляются сообщения. Просматривая все вокруг, я обнаружил этот слабый тест и упоминал, что кэшированные в IMP сообщения быстрее, чем вызовы виртуальных функций, которые, в свою очередь, быстрее, чем отправка стандартного сообщения.

Я не пытаюсь что-то оптимизировать, просто получаю более глубокое понимание того, как именно отправляются сообщения.

  • Как отправляются сообщения Obj-C?
  • Как указатели метода экземпляра кэшируются, и вы можете (в общем) сказать, прочитав код, будет ли кэшировано сообщение?
  • Методы класса по существу такие же, как функция C (или метод статического класса в C++), или есть что-то еще для них?

Я знаю, что некоторые из этих вопросов могут зависеть от реализации, но есть только одна реализация, которая действительно имеет значение.

3 ответа

Решение

Как отправляются сообщения Obj-C?

Сообщения Objective C отправляются с использованием среды выполнения objc_msgSend() функция. Показанная в документации Apple, функция принимает как минимум 2 аргумента:

  1. Принимающий объект
  2. Селектор сообщения
  3. [Переменный список аргументов отправляемого сообщения.]

Экземпляры класса имеют isa указатель, который является указателем на их объект класса. Селекторы методов в каждом объекте хранятся в "таблице" в объекте класса, а objc_msgSend() Функция следует за isa указатель на объект класса, чтобы найти эту таблицу, и проверяет, есть ли метод в таблице для класса. Если он не может его найти, он ищет метод в таблице суперкласса класса. Если не найден, он продолжает подниматься по дереву объектов, пока не найдет метод или не доберется до корневого объекта (NSObject). На данный момент, исключение выдается.

Как указатели метода экземпляра кэшируются, и вы можете (в общем) сказать, прочитав код, будет ли кэшировано сообщение?

Из руководства Apple Objective-C по обмену сообщениями:

Для ускорения процесса обмена сообщениями система времени выполнения кэширует селекторы и адреса методов по мере их использования. Для каждого класса есть отдельный кэш, и он может содержать селекторы для унаследованных методов, а также для методов, определенных в классе. Перед поиском в таблицах диспетчеризации подпрограмма обмена сообщениями сначала проверяет кэш класса принимающего объекта (согласно теории, что метод, который использовался один раз, может быть использован снова). Если селектор метода находится в кеше, обмен сообщениями только немного медленнее, чем вызов функции. Когда программа работает достаточно долго, чтобы "разогреть" свои кеши, почти все отправляемые ею сообщения находят кешированный метод. Кэши динамически растут для размещения новых сообщений во время работы программы.

Как уже говорилось, кэширование начинает происходить после запуска программы, и после того, как программа проработала достаточно долго, большинство вызовов методов будет выполняться через кэшированный метод. Как также говорится, кэширование происходит при использовании методов, поэтому сообщение кэшируется только при его использовании.

Методы класса по существу такие же, как функция C (или метод статического класса в C++), или есть что-то еще для них?

Объекты класса обрабатывают отправку метода аналогично экземплярам классов. Каждый объект класса имеет объект, который хранит свои собственные методы класса, в объекте, называемом metaclass, Объект класса имеет свой собственный isa указатель на его объект метакласса, который в свою очередь имеет объекты суперметакласса, от которых он может наследовать объекты класса. Отправка метода в методы класса выглядит так:

  1. Система диспетчеризации следует за объектом класса isa указатель на объект метакласса
  2. В таблице методов объекта метакласса ищется метод класса.
  3. Если не найдено, поиск продолжается до суперкласса объекта метакласса, где поиск продолжается.
  4. Этот процесс повторяется до тех пор, пока метод не будет найден или пока он не попадет в корневой метакласс, и не будет выдано исключение.

Я также написал инструкцию по objc_msgSend() на x86_64 в своем блоге, если кто-то хочет углубиться в:

http://www.friday.com/bbum/2009/12/18/objc_msgsend-part-1-the-road-map/

Механизмы отправки

Используется для поиска необходимого исполняемого кода при вызове метода (отправленном сообщении)

  • В соответствии
  • Статический (прямой)(C, Java, C++ по умолчанию, Swift static, final) - компилятор знает необходимую реализацию метода во время компиляции.
  • Динамический - основан на witness table(виртуальная таблица, диспетчерская таблица) и вводит полиморфизм
    • Таблица, V-таблица (С++ virtual, Java по умолчанию, Swift по умолчанию) — каждый объект имеет ссылку на класс, в котором есть таблица со всеми адресами методов (супер, переопределения, новые). SIL содержит vtableили же witness_table
    • Сообщение (Цель-C, Свифт dynamic) - Каждый объект имеет ссылку (isa) на класс , который содержит ссылку на суперкласс и таблицу отправки (которая содержит только реализованные методы (служебные и новые)) и не содержит методов из супер. Если метод не был найден в текущей таблице отправки, он продолжает поиск в таблице отправки суперкласса. Этот процесс оптимизирован кэшированием. SIL содержит volatileОтправка сообщений Objective-C

Например

      class A {
    func foo1() {}
    func foo2() {}
}
class B: A {
    override func foo2() {}
    func foo3() {}
}

Цель-C obc_msgSend

      id obc_msgSend(id self, SEL op, ...)
// self - object which receive a message
// op - selector of method
//... - arguments

Если реализация метода не была найдена для данного селектора, вы увидите следующую ошибку

      unrecognized selector sent to instance
Другие вопросы по тегам