#objective-c #dynamic #typing
#objective-c #динамическая #ввод
Вопрос:
Меня интересует, как работает динамическая типизация в Objective-C. Я изучал тип «id», я знаю, что он делает и как его использовать, но мне любопытно… Как такая функциональность реализуется под капотом?
Вы не можете определить / разрешить что-либо во время компиляции, только во время выполнения. Я предполагаю, что это может просто указывать на первый байт какого-либо объекта в памяти, но как хранится сигнатура класса? Как он узнает, на что он в данный момент указывает, и как он реализует различные методы получения для класса указанного объекта?
Ответ №1:
«Под капотом», так сказать, все объекты Objective-C являются структурами C с указателем на объект класса, который представляет их тип. id
— это указатель на самую базовую такую структуру, которая выглядит примерно так:
struct objc_object {
Class isa;
}
id
компилятор специально обрабатывает это, поскольку компилятор не выдает вам никаких предупреждений о том, что объект может не реагировать на какой-либо селектор, как это происходит при использовании более строго типизированной переменной.
Когда вы вызываете метод для любого объекта, он следует за этим isa
указателем на объект класса и ищет в этом объекте класса функцию реализации для селектора метода, который вы пытались вызвать.
Ответ №2:
Чтобы добавить к ответу Anomie, то, как класс хранит таблицу, на какие сообщения он отвечает, и какие биты кода вызывают эти сообщения, совершенно непрозрачно. Таким образом, в определенной степени никто не может точно ответить, как работает реализация Apple, и она почти наверняка отличается от реализации GNU.
Однако справочник Apple по среде выполнения Objective-C объясняет все, что может выполнять среда выполнения на уровне C. Итак, вы можете увидеть, какие операции возможны для настройки и поиска. По сути, это относительно простая система, состоящая в основном из набора словарей (в неинфлектированном смысле), которые сопоставляют одно с другим, например, из селектора в указатель функции IMP. Если в таблице есть запись для определенного класса, то вызывается соответствующая вещь. Если нет, то проверяются суперклассы, рассматривается стандартный механизм forwardingTargetForSelector: запасной вариант и так далее.
Помимо этого, более конкретные комментарии требуют более конкретных вопросов. Есть много деталей, подобных тому, что наблюдение за значением ключа достигается с помощью метода swizzle (таким образом, среда выполнения настраивает указатель C, который класс будет вызывать для установщика, на тот, который вызывает реальный установщик и информирует того, кто наблюдает), но все это просто конкретные случаи использования среды выполнения, как описано.
Комментарии:
1. Хорошее объяснение, премного благодарен!