Class objects и Objective-C runtime

При компиляции программы на Objective-C компилятор для каждого введенного класса автоматически создает так называемый class object — полноценный объект, содержащий в себе всю информацию о данном классе, включая название, суперкласс, список методов и instance-переменных.

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

Одной из особенностей class object’а является то, что он поддерживает все методы класса NSObject, то есть когда ему посылается сообщение, то в начале идет поиск среди методов класса, а если метод не найден, то поиск продолжается среди instance-методов класса NSObject.

Ещё одной интересной особенностью является возможность инциализации class object’ов — в начале работы приложения каждому class object’у посылается сообщение (класса) initialize.

Это сообщение гарантированно посылается каждому class object’у, причем всего один раз и до того, как ему будет послано любое другое сообщение. Простейшим примером примененния такого сообщения является реализация Singleton’ов — именно в методе initialize следует создать тот самый единственный экземпляр объекта и запомнить его в static-переменной.

Если посмотреть на Objective-C runtime от Apple, то мы найдем большое количество С-функций, служащих для работы с классами (непосредственно во время выполения программы).

Наиболее интересными являются следующие:

Method   class_getInstanceMethod( Class aClass, SEL aSelector );
Method   class_getClassMethod   ( Class aClass, SEL aSelector );
struct objc_method_list * class_nextMethodList(Class theClass, void ** iterator);
void     class_addMethods       ( Class aClass, struct objc_method_list * methodList );
void     class_removeMethods    ( Class aClass, struct objc_method_list * methodList );
unsigned method_getNumberOfArguments ( Method method );
unsigned method_getSizeOfArguments   ( Method method );
unsigned method_getArgumentInfo      ( Method method, int argIndex, const
                                       char ** type, int *  offset );
Ivar     class_getInstanceVariable   ( Class aClass, const char * aVariableName );

Функция class_getInstanceMethod возвращает указатель на структуру (objc_method), описывающую заданный instance-метод данного класса.

Функция class_getClassMethod возвращает указатель на структуру (objc_method), описывающую заданный метод данного класса.

Функция class_nextMethodList возвращет один из списков методов для заданного класса. Приводимый ниже фрагмент кода позволяет перебрать все методы для данного класса.

    void                    * iterator = 0;
    struct objc_method_list * mlist;

    //
    // Each call to class_nextMethodList returns one methodList
    //

    methodList = class_nextMethodList( classObject, &iterator  )

    while ( methodList != NULL )
    {
        // …do something with the method list here…

        methodList = class_nextMethodList ( classObject, &iterator  );
    }

Функция class_addMethods позволяет добавлять новые методы к заданному классу.

Функция class_removeMethods позволяет убирать методы из заданного класса.

Функция method_getNumberOfArguments Возвращает количество аргументов для заданного метода.

Функция method_getSizeOfArguments возвращает размер места на стеке, занимаемого всеми аргументами данного метода.

Функция method_getArgumentInfo возвращает информацию об одном из аргументов для заданного метода..

Функция class_getInstanceVariable возвращает информацию об instance-переменной класса в виде указателя на структуру objc_ivar.

Для кодирования информации о типах используется специальное строковое представление, однозначно сопоставляющее каждому типу данных некоторую строку. Явно получить такую строку для проивзольного типа можно при помощи конструкции @encode ().

char * buf1 = @encode ( int ** );
char * buf2 = @encode ( struct key );
char * buf3 = @encode ( Rectangle );

Автор: Алексей Боресков

Метки:

Если вам понравилась статья, подпишитесь на RSS!