2013-04-09 4 views
8

class_getInstanceMethodで取得されたメソッドがクラス階層のどこにあるのかを見つけることはできますか?たとえば、クラスAがmyMethodを実装しているとします。今私はクラスA1のクラスAをサブクラス化したと言う。私がclass_getInstanceMethod(ClassA1, myMethod)と呼んだ場合、結果のメソッドがClassA1でオーバーライドされたのか、それともA1から直接渡されたのかを知ることは可能ですか?class_getInstanceMethodの使用 - クラス階層に実装されているメソッドはどこですか?

あなたはいつもクラスにアクセスすることができ、私はあなたがにClassAとClassA1の両方へのアクセスを持っていた場合、のIMPのメモリアドレスを比較することが可能であると仮定し、私はA.

答えて

15

に直接アクセスすることはできません。同じSELを持つclass_getInstanceMethodまたはclass_getMethodImplementationに渡して、IMPのアドレスを比較して、メソッドがサブクラスによってオーバーライドされているかどうかを確認してください。

このメソッドを定義するルートクラスを取得する場合は、少し毛深くなります。

とにかく、ここに行く:

static inline BOOL isInstanceMethodOverridden(Class cls, SEL selector, Class *rootImpClass) { 
    IMP selfMethod = class_getMethodImplementation(cls, selector); 
    BOOL overridden = NO; 
    Class superclass = [cls superclass]; 
    while(superclass && [superclass superclass]) { 
     IMP superMethod = class_getMethodImplementation(superclass, selector); 
     if(superMethod && superMethod != selfMethod) { 
      overridden = YES; 
      if(!rootImpClass) { 
       //No need to continue walking hierarchy 
       break; 
      } 
     } 

     if(!superMethod && [cls respondsToSelector:selector])) { 
      //We're at the root class for this method 
      if(rootImpClass) *rootImpClass = cls; 
      break; 
     } 

     cls = superclass; 
     superclass = [cls superclass]; 
    } 

    return overridden; 
} 
+2

このようなNSProxy' ''などNSObject'のサブクラスを作成していないオブジェクト、失敗します –

+0

この素晴らしいです。ただのメモ。 –

+0

@ RichardJ.RossIII更新された参照してください。 :) –

3

ここでヤコブのコードの私の修正版です。 class_getMethodImplementationがメソッドをオーバーライドとして扱う原因となっていた_objc_msgForwardを返すので、私は彼に問題がありました。私はまた、* rootImpClassを必要としなかったが、に戻って追加することは十分に簡単です。

inline BOOL isInstanceMethodOverridden(Class cls, SEL selector) 
{ 
    IMP selfImplementation = class_getMethodImplementation(cls, selector); 

    BOOL overridden = NO; 
    Class superclass = cls; 

    while ((superclass = [superclass superclass])) 
    { 
     Method superMethod = class_getInstanceMethod(superclass, selector); 
     if (superMethod && method_getImplementation(superMethod) != selfImplementation) 
     { 
      overridden = YES; 
      break; 
     } 
    } 

    return overridden; 
} 
関連する問題