Вызов супер в категории такой же, как вызов в подклассе - PullRequest
12 голосов
/ 29 мая 2011

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

Ответы [ 4 ]

14 голосов
/ 30 мая 2011

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

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

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

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

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

Пост Итая отвечает на вопрос более прямо, но в коде:

@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 См. Реферат Грега Паркера [Объяснение объекта]: Классы и мета-классы

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

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

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

8 голосов
/ 29 мая 2011

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

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

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

2 голосов
/ 29 мая 2011

Учитывая приведенный ниже пример, 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) есть дополнительные действия, они делают разные вещи.

0 голосов
/ 29 мая 2011

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

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

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

@implementation categoryTestViewController (ShadowBar)
- (void)viewDidAppear:(BOOL)animated {
    //draw the shadow ui nav bar
    NSLog(@"super's class = %@, self's 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's class = categoryTestViewController, self's class categoryTestViewController
2011-05-29 08:06:16.201 categoryTest[9833:207] yeah they are the same

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

...