8

是否可以在类层次结构中找到所检索的方法class_getInstanceMethod来自何处?例如,假设 A 类实现了 myMethod。现在说我在 A1 类中对 A 类进行了子类化。如果我打电话class_getInstanceMethod(ClassA1, myMethod),是否可以判断结果方法是在 ClassA1 中被覆盖还是直接来自 A1?

我想如果您可以访问 ClassA 和 ClassA1,则可以比较 IMP 的内存地址,但我无法直接访问 A。

4

2 回答 2

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;
}
于 2013-04-09T18:24:43.153 回答
3

这是我对 Jacob 代码的修改版本。我遇到了他的问题,因为 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;
}
于 2014-02-04T03:51:48.547 回答