7

Objective-C を使用したプログラミングの Apple の「メッセージング」の章を読みましたが、self と super についていくつか質問があります。私の知る限り、コンパイラがメッセージを見つけると、レシーバー、セレクター、およびセレクターの可変引数を使用して、それを objc_msgSend に変換します。たとえば[self test]、次のようになります。

objc_msgSend(self, @selector(test));

レシーバーのディスパッチ テーブルにメソッドの実装がない場合、関数はスーパークラスで実装を見つけようとします。super は、コンパイラが現在のオブジェクトのスーパークラスでメソッド実装の検索を開始するための単なるフラグであり、ドキュメントでは、コンパイラが「スーパー」を見つけると、次のように変換すると述べています。

struct objc_super mySuperClass = {
    self,
    [self superclass]
};
objc_msgSendSuper(&mySuperClass, @selector(forwardedMethod));

私は 3 つのクラスを持つプロジェクトを作成しました。それぞれが別のクラスを継承しています。

@interface FirstClass : NSObject
- (void)forwardMethod;
@end

@interface SecondClass : FirstClass
@end

@interface ThirdClass : SecondClass
@end

ルート ビュー コントローラーで 3 番目のクラスのインスタンスを作成し、'forwardMethod' というメソッドを呼び出します。実装:

//First Class
- (void)forwardMethod {
   NSLog(@"Base class reached");
}

//SecondClass imp
- (void)forwardMethod {
   NSLog(@"second class");
   [super forwardMethod];
}

//ThirdClass imp
- (void)forwardMethod {
   NSLog(@"third class");
   [super forwardMethod];
}

すべて正常に動作します。しかし、その後、コンパイラを解釈することにしました:

//First Class
- (void)forwardMethod {
   NSLog(@"Base class reached");
}

//SecondClass imp
- (void)forwardMethod {
   NSLog(@"second class");
   struct objc_super mySuperClass = {
      self,
      [self superclass]
   };

   objc_msgSendSuper(&mySuperClass, @selector(forwardMethod));
}

//ThirdClass imp
- (void)forwardMethod {
   NSLog(@"third class");
    struct objc_super mySuperClass = {
        self,
        [self superclass]
    };

    objc_msgSendSuper(&mySuperClass, @selector(forwardMethod));
}

これにより、2 番目のクラス「forwardMethod」が再帰的に呼び出されます。self と [self superclass] を使用して 2 番目のクラスで 'forwardMethod' に構造体を作成しますが、self は 3 番目のクラスであり
、私のスーパークラスは常に '2 番目のクラス' になります。たぶん私は何か間違ったことをしているのですが、基本クラスの「フォワードメソッド」にアクセスするにはどうすればよいですか?

4

2 に答える 2

4

SecondClass では、この構造体に ThirdClass とまったく同じ内容が入力されます。

   struct objc_super mySuperClass = {
      self,
      [self superclass]
   };

selfどちらの場合も同じ値を持つため、[self superclass]ThirdClass のインスタンスから呼び出された場合は常に SecondClass になります (実際の実装 (コード) が SecondClass に存在する場合でも)。コンパイラーが発行するものにはもう少し魔法があります (objc_msgSendSuper は非常に単純です)。クラスへの参照を発行する必要があるため、ポージングや isa ポインター操作 (悪いプログラマー、ドーナツはありません)期待どおりに動作します。それがどのように機能するかを正確に知るために、長い間詳細を調べていません。

ランタイムコンパイラのソースが利用可能です。

于 2013-06-30T18:47:01.647 に答える