理解客观的超级c

时间:2012-08-25 14:53:59

标签: objective-c inheritance

请考虑以下代码:

  `@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:

1 个答案:

答案 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