请考虑以下代码:
`@interface Parent : NSObject
- (void)whoAmI;
@end
@implementation Parent
- (void)whoAmI
{
NSLog(@"PARENT CALLED");
}
@end
@interface Child : Parent
- (void)test;
@end
@implementation Child
- (void)whoAmI
{
NSLog(@"CHILD CALLED");
}
- (void)test
{
NSLog(@"%@", [super class]);// CHILD!!!! why???
[super performSelector:@selector(whoAmI)];// "CHILD CALLED" why???
}
@end
`
当我调用test
方法时,我希望看到父类打印并执行父whoAmI
方法。但令人惊讶的是,两次派生类都被调用。任何人都可以解释它为什么会发生,我如何在基类上performSelector:
?
答案 0 :(得分:5)
super
方法只是将消息转发到超类的实现代码的一种方式。但是,self
保持不变。实际上,如果您创建Child
的实例,则根本没有Parent
的实例。您可以通过NSLog-ing self
作为%p
来测试它,以检查指针地址;调用super方法时,self
指针与调用它的子类实例的指针相同:
父:
- (void)printAddr {
NSLog(@"%p", self);
}
子:
- (void)printAddr {
NSLog(@"sub: %p, self");
[super printAddr];
}
如果您拨打[aChild printAddr];
,您会看到指针是相同的。
现在让我们将其转化为解决您的具体问题。首先,看看performSelector:方法。它的默认实现是在NSObject中,这个实现很可能使用self
来调用选择器。因此,即使方法实现是NSObject的方法实现,仍然会在 real 对象(您的子类)上调用该方法。如果不是这种行为,performSelector:总是会尝试调用该方法,就好像它是直接在NSObject上实现的,除非你在子类上实现了自己的performSelector:显然,这是错误的行为。
此外,-class
方法也是如此。它的默认实现驻留在NSObject上,显然它总是返回[NSObject class]
是无聊的id,所以相反它有效地使用self
来获取真实对象的类。 / p>
你也可以通过在超类上调用另一种方法self
来测试我在这里所说的内容。即使您使用super
来调用第一个方法,仍然会在您的子类上调用第二个方法,因为self
仍然指向子类:
父:
- (void)method {
NSLog(@"Parent: method");
[self method1];
}
- (void)method1 {
NSLog(@"Parent method1");
}
子:
- (void)method {
[super method];
}
- (void)method1 {
NSLog(@"Child: method1");
}
在这种情况下,[aChild method]
将输出:
Parent: method
Child: method1