Вызов [[super allocWithZone:nil] init], механизма обмена сообщениями

ф. е. (просто для более ясного понимания механизма сообщений) У меня есть класс

МойКласс.h

@interface MyClass : NSObject {
   int ivar1;
   int ivar2;
}

+ (id)instance;

@end

МойКласс.м

static MyClass* volatile _sInstance = nil;

@implementation MyClass

+ (id)instance {
       if (!_sInstance) {
       @synchronized(self) {
           if (!_sInstance) {
               _sInstance = [[super allocWithZone:nil] init];
           }
       }
   }
   return _sInstance;
}

@end

Что на самом деле будет отправлено в objc_msgSend при вызове [super allocWithZone:nil] ?

objc_msgSend([MyClass class], "allocWithZone", nil) or objc_msgSend([NSObject class], "allocWithZone", nil) ?

На практике я думаю, что называется objc_msgSend(self, "allocWithZone", nil) и в этом случае self == [MyClass class];

Я хочу быть уверен, что память для ivar1 и ivar2 будет выделена.

Правда ли, что когда мы вызываем super в методе класса, в функцию objc_msgSend() передается аргумент «я», который в нашем случае является объектом класса ребенка? И allocWithZone будет "смотреть" объект дочернего класса, чтобы увидеть, сколько памяти должно быть выделено для ivar1 и ivar2.

Спасибо!


person BergP    schedule 15.08.2013    source источник
comment
Может быть, я что-то упускаю, зачем вам выделять экземпляр MyClass, вызывая [[MyClass super] alloc]?   -  person trojanfoe    schedule 15.08.2013
comment
@trojanfoe Это может быть метод alloc, это не так важно )   -  person BergP    schedule 15.08.2013
comment
Но чего я не понимаю, так это того, как вызов [super alloc] (или [super allocWithZone]) выделит достаточно места для дополнительных переменных экземпляра в self?   -  person trojanfoe    schedule 15.08.2013
comment
Так что это был мой вопрос) Я думаю, что будет передано self, которое будет [класс MyClass], и из [класса MyClass] будет видно, сколько места будет достаточно   -  person BergP    schedule 15.08.2013
comment
@trojanfoe Неважно, вызывать ли alloc с помощью super или self. Среда выполнения использует приемник для определения размера экземпляра.   -  person Nikolai Ruhe    schedule 15.08.2013
comment
Как поясняет мой ответ, супервызов отправляет в среду выполнения как суперкласс, так и получатель. Тогда в реализацию метода передается только получатель.   -  person Nikolai Ruhe    schedule 15.08.2013
comment
@NikolaiRuhe Хорошо, спасибо - интересно.   -  person trojanfoe    schedule 15.08.2013


Ответы (1)


Любое сообщение для super преобразуется компилятором в objc_msgSendSuper (не objc_msgSend). Первый аргумент — указатель на структуру. Структура содержит указатель на суперкласс текущей реализации и указатель на приемник. Первый нужен во время выполнения для поиска переопределенной реализации, второй используется в качестве первого аргумента.

В случае метода класса получатель снова является указателем класса, но не таким, как super_class. В вашем случае приемник является указателем MyClass, а указатель super_class будет NSObject.

Два примечания: я рекомендую не тратить силы на написание самого причудливого Синглтона. Лучше предоставить разработчику возможность создавать свои собственные экземпляры или использовать предоставленный общий экземпляр. Обратите внимание, что блокировка с двойной проверкой не работает.

person Nikolai Ruhe    schedule 15.08.2013