8

によって取得されたメソッドがクラス階層のどこclass_getInstanceMethodから来ているかを見つけることは可能ですか? たとえば、クラス A が myMethod を実装するとします。ここで、クラス A1 でクラス A をサブクラス化したとします。を呼び出しclass_getInstanceMethod(ClassA1, myMethod)た場合、結果のメソッドが ClassA1 でオーバーライドされたのか、それとも A1 から直接取得されたのかを判断できますか?

ClassA と ClassA1 の両方にアクセスできる場合、IMP のメモリ アドレスを比較することは可能だと思いますが、A に直接アクセスすることはできません。

4

2 に答える 2

15

クラスのスーパークラスにはいつでもアクセスできるため、それを一緒に、class_getInstanceMethodまたはclass_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

これは、ジェイコブのコードの私の修正版です。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 に答える