Ответ 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, но я думаю, что это, вероятно, просто грязное и без того неудобное объяснение.