Вызывает ли вызов [super init]
то же самое в категории как подкласс? Если нет, то какая разница?
Является ли вызов super в категории тем же самым, что и вызов его в подклассе?
Ответ 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:] приведет к вызову ничего... не к циклу, поэтому я не знаю, что он там действительно делает.