Динамическая типизация, Objective-C, как она работает?

Мне интересно, как работает динамический ввод в Objective-C. Я изучаю тип "id", я знаю, что он делает и как его использовать, но мне любопытно... Как реализовать такие функции под капотом?

Вы не можете определять/разрешать что-либо во время компиляции, только во время выполнения. Я думаю, это может просто указать на первый байт некоторого объекта в памяти, но как хранится подпись класса? Как он знает, что он сейчас указывает на и как он реализует различные геттеры для класса заостренного объекта?

Ответ 1

"Под капотом", так сказать, все объекты Objective-C представляют собой C-структуры с указателем на объект класса, который представляет их тип. id является указателем на самую основную такую ​​структуру, которая выглядит примерно так:

struct objc_object {
    Class isa;
}

id обрабатывается специально компилятором, поскольку компилятор не дает вам никаких предупреждений о том, что объект не может отвечать на какой-либо селектор, как при использовании более строго типизированной переменной.

При вызове метода на любом объекте следует, что isa указатель на объект класса и ищет объект класса для поиска функции реализации для селектора метода, который вы пытались вызвать.

Ответ 2

Чтобы добавить к анонимному ответу, как класс хранит таблицу, на какие сообщения она отвечает, и какие биты кода, вызываемые этими сообщениями, полностью непрозрачны. Таким образом, степень, в которой никто не может точно ответить, как работает Apple, и почти наверняка отличается от реализации GNU.

Однако Apple Objective-C Runtime Reference объясняет все, что может выполнять среда выполнения, на уровне C. Таким образом, вы можете видеть, какие операции возможны для настройки и поиска вещей. Это относительно простая система под капотом, в первую очередь просто куча словарей (в незавидном смысле), которые сопоставляют одну вещь с другой, например, от селектора до указателя функции IMP. Если есть запись в таблице для определенного класса, тогда вызывается соответствующая вещь. Если не проверены суперклассы, рассматривается стандартный резервный механизм forwardingTargetForSelector: и т.д.

Кроме того, более конкретные комментарии требуют более конкретных вопросов. Существует множество подробностей, подобных тому, что наблюдение за ключевыми значениями достигается методом swizzle (поэтому среда выполнения корректирует указатель C, который класс будет вызывать для сеттера как тот, который вызывает реальный сеттер, и информирует о том, кто наблюдает), но все они являются просто конкретным использованием среды выполнения, как описано.