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-ingself%p使用してポインタアドレスを検査することでテストできます。スーパーメソッドが呼び出されると、selfポインターはそれを呼び出したサブクラスのインスタンスの場合と同じになります。

親:

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

子:

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

を呼び出すと、ポインタが同じであることがわかります[aChild printAddr];

それでは、これを特定の質問に対処するように変換しましょう。まず、performSelector:メソッドを見てください。そのデフォルトの実装はNSObjectにあり、この実装はおそらくselfセレクターの呼び出しに使用します。このため、メソッドの実装はNSObjectの実装ですが、メソッドは実際のオブジェクトであるサブクラスで呼び出されます。この動作がなかった場合、performSelector:は、独自のperformSelector:をサブクラスに実装しない限り、NSObjectに直接実装されているかのように常にメソッドを呼び出そうとします。明らかに、これは間違った動作です。

さらに、同じことがメソッドにも当てはまります-class。そのデフォルトの実装はNSObjectにあり、明らかに常に返される退屈なIDである[NSObject class]ため、代わりに実際のオブジェクトselfのクラスを取得するために効果的に使用します。

で別のメソッドを呼び出すスーパークラスでメソッドを作成することにより、ここで言ったことをテストすることもできますselfsuper最初のメソッドを呼び出すために使用する場合でもself、サブクラスを指しているため、2番目のメソッドはサブクラスで呼び出されます。

親:

- (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 に答える