2013-04-09 80 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; 
}