1

请考虑以下代码:

  `@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:在基类上?

4

1 回答 1

5

super方法只是将消息转发到超类的实现代码的一种方式。但是,self保持不变。实际上,如果您创建 的实例Child,则根本没有 的实例Parent。您可以通过 NSLog-ing 对其进行测试,self%p检查指针地址;当调用超级方法时,self指针与调用它的子类实例的指针相同:

家长:

- (void)printAddr {
    NSLog(@"%p", self);
}

孩子:

- (void)printAddr {
    NSLog(@"sub: %p, self");
    [super printAddr];
}

如果您调用 ,您将看到指针是相同的[aChild printAddr];

现在让我们将其转化为解决您的具体问题。首先,看一下 performSelector: 方法。它的默认实现在 NSObject 中,这个实现很可能用于self调用选择器。因此,即使方法实现是 NSObject 的,该方法仍然会在真实对象上调用,即您的子类。如果不是因为这种行为, performSelector: 将始终尝试调用该方法,就好像它直接在 NSObject 上实现一样,除非您在子类上实现了自己的 performSelector: ;显然,这是错误的行为。

此外,该方法同样适用-class。它的默认实现驻留在 NSObject 上,显然它总是返回的 id 很无聊[NSObject class],因此它有效地用于self获取真实对象的类。

您还可以通过在超类上创建一个调用另一个方法的方法来测试我在这里所说的内容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
于 2012-08-25T15:36:05.267 回答