← Назад к вопросам

Что такое Runtime?

2.3 Middle🔥 151 комментариев
#UIKit и верстка

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Objective-C Runtime?

Runtime (или среда выполнения) в контексте iOS/macOS разработки — это фундаментальный компонент языка Objective-C, представляющий собой набор функций и структур данных в языке C, который обеспечивает динамическую природу Objective-C во время выполнения программы. Это то, что превращает статический код в динамически работающее приложение.

Основные концепции и компоненты Runtime

На низком уровне Runtime состоит из нескольких ключевых структур:

  1. objc_object и objc_class: Базовая структура для любого объекта (id — это указатель на objc_object) и класса.

    // Упрощённое представление (реальная структура скрыта)
    struct objc_object {
        Class isa; // Указатель на класс объекта
    };
    
    struct objc_class {
        Class isa;                // Мета-класс
        Class super_class;        // Указатель на суперкласс
        const char *name;         // Имя класса
        long version;
        long info;
        long instance_size;
        struct objc_ivar_list *ivars;     // Список переменных экземпляра (ivar)
        struct objc_method_list **methodLists; // Список методов
        struct objc_cache *cache;         // Кэш для ускорения поиска методов
        struct objc_protocol_list *protocols; // Список протоколов
    };
    
  2. SEL (Selector): Уникальный идентификатор имени метода (символа компиляции). По сути, это C-строка, но для сравнения используется адрес в памяти, что делает сравнение селекторов очень быстрым (@selector(viewDidLoad)).

  3. IMP (Implementation Pointer): Указатель на фактическую реализацию метода — адрес в памяти, где начинается C-функция, соответствующая методу. Имеет тип id (*IMP)(id, SEL, ...).

  4. Method: Структура, связывающая SEL (имя метода) и IMP (его реализацию).

Как работает вызов метода (Message Passing)

В отличие от "вызова функции" в C++, Objective-C использует отправку сообщений (message passing). Это фундаментальное различие.

// Код, который мы пишем:
[myObject doSomethingWithParam:param];

// Компилятор преобразует это в вызов функции runtime:
objc_msgSend(myObject, @selector(doSomethingWithParam:), param);

Функция objc_msgSend (и её варианты) выполняет следующую динамическую последовательность:

  1. Проверяет, не nil ли объект-получатель (myObject).
  2. Находит isa указатель объекта, чтобы получить его класс.
  3. Ищет реализацию метода (IMP) в кэше методов класса по ключу SEL (это очень быстрая хэш-таблица).
  4. Если в кэше нет, проходит по списку методов класса.
  5. Если метод не найден в классе, через указатель super_class начинает поиск в иерархии суперклассов.
  6. Если метод так и не найден, запускается механизм пересылки сообщений (message forwarding) (forwardInvocation:), который даёт объекту последний шанс обработать сообщение, или генерируется исключение unrecognized selector sent to instance.

Эта динамичность обеспечивает ключевые возможности Objective-C.

Возможности, предоставляемые Runtime

  • Динамическое создание и изменение классов: Можно создавать классы, добавлять методы и переменные прямо во время выполнения.
    Class newClass = objc_allocateClassPair([NSObject class], "MyDynamicClass", 0);
    class_addMethod(newClass, @selector(greet), (IMP)greetImplementation, "v@:");
    objc_registerClassPair(newClass);
    
  • Категории (Categories): Возможность добавлять методы к существующим классам без наследования. На уровне runtime методы категории добавляются в список методов оригинального класса.
  • Ассоциативные ссылки (Associated Objects): Позволяют прикреплять произвольные данные к объекту через ключ, эмулируя добавление свойств в категориях. Используется внутри @property в категориях.
    objc_setAssociatedObject(self, &key, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
  • Метод своппинг (Method Swizzling): Замена реализации одного метода другой во время выполнения. Мощный, но опасный инструмент для отладки, исправления багов в сторонних библиотеках или добавления сквозной функциональности (логирование, аналитика).
    Method originalMethod = class_getInstanceMethod([UIViewController class], @selector(viewWillAppear:));
    Method swizzledMethod = class_getInstanceMethod([UIViewController class], @selector(my_viewWillAppear:));
    method_exchangeImplementations(originalMethod, swizzledMethod);
    
  • Интроспекция (Introspection): Возможность исследовать объект во время выполнения: узнать его класс (isKindOfClass:), проверить наличие метода (respondsToSelector:), получить список свойств и методов.
  • Протоколы и неформальные протоколы: Проверка соответствия объекта протоколу (conformsToProtocol:) также реализована через runtime.

Runtime в современном Swift

Swift — это в основном статический язык, но он сохраняет совместимость с Objective-C Runtime для классов, наследующихся от NSObject, и методов, помеченных как @objc или dynamic. Это позволяет:

  • Использовать KVO (Key-Value Observing) с @objc dynamic свойствами.
  • Взаимодействовать с API, написанными на Objective-C (например, таргетинг селекторов, IBAction).
  • Использовать механизмы вроде unrecognized selector, своппинга (с большой осторожностью) через method_exchangeImplementations.

Однако "чистые" Swift-классы (не от NSObject) и их методы не участвуют в этой динамической системе. Их диспетчеризация методов оптимизирована компилятором (прямые вызовы, виртуальные таблицы) и происходит значительно быстрее.

Итог: Objective-C Runtime — это "сердце" динамической природы Cocoa и Cocoa Touch. Он превращает статический код в живое, гибкое приложение, позволяя объектам взаимодействовать через отправку сообщений, изменять свою структуру на лету и интроспектировать себя. Понимание его основ критически важно для решения сложных задач, глубокой отладки и написания мощных, гибких фреймворков, даже в эпоху Swift.