Как вызвать метод super.super?
Я хочу вызвать метод суперкласса суперкласса, не нарушая цепочку наследования. Что-то вроде этого:
+(id) alloc
{
return [super.super alloc];
}
Есть ли способ достичь этого?
Не путайте с предложением поведения методом superclass
, обсуждаемым здесь.
UPD:
Несколько слов о различиях super
и superclass
.
Допустим, что мы имеем AClass
и SuperAClass
. Как следует из их имен AClass
наследует SuperAClass
. Каждый из них имеет реализацию метода -(void) foo;
AClass
реализует один из следующие методы класса:
1. суперкласс:
+(id) alloc {
return [[self superclass] alloc];
}
2. супер:
+(id) alloc {
return [super alloc];
}
Теперь предположим, что эти 2 строки кода:
AClass *AClassInstance = [AClass alloc];
[AClassInstance foo];
В первом случае (с использованием суперкласса) будет вызываться метод SuperAClass
foo
.
Для второго случая (с использованием супер) будет вызываться метод AClass
foo
.
Ответы
Ответ 1
В вашем конкретном примере +superclass
- это на самом деле способ:
+ (id)someClassMethod {
return [[[self superclass] superclass] someClassMethod];
}
так как это метод класса, поэтому self
относится к объекту класса, где +someClassMethod
определяется.
С другой стороны, вещи становятся более сложными в методах экземпляра. Одним из решений является получение указателя на реализацию метода в классе supersuper (grandparent). Например:
- (id)someInstanceMethod {
Class granny = [[self superclass] superclass];
IMP grannyImp = class_getMethodImplementation(granny, _cmd);
return grannyImp(self, _cmd);
}
Аналогично примеру метода класса +superclass
отправляется дважды, чтобы получить суперсуперкласс. IMP
является указателем на метод, и мы получаем IMP для метода, имя которого совпадает с текущим (-someInstaceMethod
), но указывая на реализацию в суперсуперклассе, а затем вызывает его. Обратите внимание, что вам нужно настроить его, если есть аргументы метода и возвращаемые значения, отличные от id
.
Ответ 2
Благодаря Bavarious, который вдохновил меня на привлечение персонала во время работы.
Вкратце, желаемая гипотетическая линия:
return [super.super alloc];
можно преобразовать в этом "реальном":
return method_getImplementation(class_getClassMethod([[self superclass] superclass], _cmd))([self class], _cmd);
Чтобы сделать его более понятным, его можно развернуть следующим образом:
Method grannyMethod = class_getClassMethod([[self superclass] superclass], _cmd);
IMP grannyImp = method_getImplementation(grannyMethod);
return grannyImp([self class], _cmd);