2013-04-09 32 views
8

是否可以找到類別層次結構中由class_getInstanceMethod檢索的方法來自哪裏?例如,說A類實現myMethod。現在說我已經在A1類中分類了A類。如果我打電話class_getInstanceMethod(ClassA1, myMethod),是否可以判斷生成的方法是在ClassA1中被覆蓋還是直接從A1中覆蓋?使用class_getInstanceMethod - 其中是在類層次結構中實現的方法嗎?

我想這將有可能比較IMP的內存地址,如果你有機會訪問都ClassA和ClassA1,但我沒有A.直接訪問

回答

15

您可以隨時訪問類超類,所以你可以將它傳遞給class_getInstanceMethodclass_getMethodImplementation使用相同的SEL並比較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

這是真棒 – 2013-04-09 19:49:55

+0

這將對於不繼承'NSObject'對象,如'NSProxy'失敗。只是一個筆記。 – 2013-05-07 22:58:55

+0

@ RichardJ.RossIII查看更新。 :) – 2013-07-18 21:19:44

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; 
}