Подтвердить что ты не робот

Является ли вызов super в категории тем же самым, что и вызов его в подклассе?

Вызывает ли вызов [super init] то же самое в категории как подкласс? Если нет, то какая разница?

4b9b3361

Ответ 1

Чтобы понять это, вероятно, важно понять, как объект хранится во время выполнения. Существует объект класса 1 который содержит все реализации метода, и отдельно существует структура с хранилищем для переменных экземпляра. Все экземпляры класса совместно используют один объект класса.

Когда вы вызываете метод в экземпляре, компилятор превращает это в вызов objc_msgSend; реализация метода просматривается в объекте класса, а затем запускается с экземпляром в качестве аргумента.

Ссылка на super вступает в силу во время компиляции, а не время выполнения. Когда вы пишете [super someMethod], компилятор превращает это в вызов objc_msgSendSuper вместо обычного objc_msgSend. Это начинает искать реализацию метода в объекте класса суперкласса, а не объект класса экземпляра. 2

Категория просто добавляет методы к объекту класса; он мало или вообще не имеет отношения к подклассу.

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

Сообщение Itai отвечает на вопрос более прямо, но в коде:

@interface Sooper : NSObject {}
- (void) meth;
@end

@interface Sooper ()
- (void) catMeth;
@end

@interface Subb : Sooper {}
- (void) subbMeth;
@end

@interface Subb ()
- (void) catSubbMeth;
@end

@implementation Sooper
- (void) meth {
    [super doIt];    // Looks up doIt in NSObject class object
}

- (void) catMeth {
    [super doIt];    // Looks up doIt in NSObject class object
}
@end

@implementation Subb
- (void) subbMeth {
    [super doIt];    // Looks up doIt in Sooper class object
}

- (void) catSubbMeth {
    [super doIt];    // Looks up doIt in Sooper class object
}
@end

1 См. Greg Parker writeup [objc explain]: Классы и метаклассы

2 Важно отметить, что метод не вызывается на экземпляр суперкласса. Здесь происходит разделение методов и данных. Метод все равно вызывается в том же экземпляре, в котором был записан [super someMethod], то есть экземпляр подкласса, используя данные этого экземпляра; он просто использует реализацию суперкласса метода.

Итак, вызов [super class] переходит к объекту суперкласса, находит реализацию метода с именем class и вызывает его в экземпляре, преобразуя его в эквивалент [self theSuperclassImplementationOfTheMethodNamedClass]. Поскольку весь этот метод возвращает класс экземпляра, на который он был вызван, вы не получаете класс суперкласса, вы получаете класс self. В связи с этим вызов class является довольно плохой проверкой этого явления.

Весь этот ответ полностью игнорирует различие в передаче сообщений и методах. Это важная особенность ObjC, но я думаю, что это, вероятно, просто грязное и без того неудобное объяснение.

Ответ 2

Нет, они делают разные вещи. Представьте структуру классов следующим образом: NSObject = > MyObject = > MySubclass, и скажите, что у вас есть категория на MyObject, называемая MyCategory.

Теперь вызов из MyCategory сродни вызову из MyObject, и поэтому super указывает на NSObject, а вызов [super init] вызывает метод NSObject -init. Однако вызов из подкласса super указывает на MyObject, поэтому инициализация с помощью super вызывает метод MyObject -init, который, если он не переопределен, ведет себя иначе, чем NSObject.

Эти два поведения отличаются друг от друга, поэтому будьте осторожны при инициализации с использованием категорий; категории не являются подклассами, а скорее дополнениями к текущему классу.

Ответ 3

В приведенном ниже примере super вызовет UIView init (не UINavigationBar метод init)

@implementation UINavigationBar (ShadowBar)
- (void)drawRect:(CGRect)rect {
    //draw the shadow ui nav bar
    [super init];
}
@end

Если вы подклассифицируете его, [super init] вызовет метод UINavigationBar init.

Итак, если есть дополнительные вещи, которые вы сделаете в UINavigationBar init (дополнительно от UIView), они будут делать разные вещи.

Ответ 4

Изменить: следующее построено на ошибочной предпосылке, пожалуйста, посмотрите на ответ josh.

не удаляет, все еще интересную ссылку на что-то, что может потенциально привести вас в заблуждение.

Это одно и то же... без ссылок на какие-либо внешние соображения, которые, возможно, были у вас, где вы заявили, что я должен... "ответить на академический вопрос с академическим ответом"

@implementation categoryTestViewController (ShadowBar)
- (void)viewDidAppear:(BOOL)animated {
    //draw the shadow ui nav bar
    NSLog(@"super class = %@, self class %@",[super class],[self class]);
    if ([self class] == [super class]) {
        NSLog(@"yeah they are the same");
    }
}
@end

выходы:

2011-05-29 08:06:16.198 categoryTest[9833:207] super class = categoryTestViewController, self class categoryTestViewController
2011-05-29 08:06:16.201 categoryTest[9833:207] yeah they are the same

и вызов [super viewDidAppear:] приведет к вызову ничего... не к циклу, поэтому я не знаю, что он там действительно делает.