2013-04-09 11 views
8

Czy możliwe jest ustalenie, skąd w hierarchii klas pochodzi metoda pobrana przez class_getInstanceMethod? Na przykład, powiedz klasa A implementuje myMethod. Teraz mówię, że mam podklasę klasy A w klasie A1. Jeśli zadzwonię pod numer class_getInstanceMethod(ClassA1, myMethod), czy można stwierdzić, czy otrzymana metoda została nadpisana w klasie A1, czy pochodzi bezpośrednio z A1?Using class_getInstanceMethod - gdzie jest metoda zaimplementowana w hierarchii klas?

Przypuszczam, że byłoby to możliwe, aby porównać adresy pamięć o IMP gdybyś miał dostęp zarówno ClassA i ClassA1, ale nie mają bezpośredniego dostępu do A.

Odpowiedz

15

można zawsze uzyskać dostęp do klasy nadklasy, dzięki czemu można przekazać ją do class_getInstanceMethod lub class_getMethodImplementation z tym samym SEL i porównać adresy IMP, aby zobaczyć, czy metoda została nadpisana przez podklasę.

To staje się bardziej owłosione, jeśli chcesz dostać się do klasy głównej, która definiuje tę metodę.

Zresztą, tu idzie:

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

to jest niesamowite –

+0

to zawiedzie dla obiektów, które nie podklasa 'NSObject', takich jak' NSProxy'. Tylko uwaga. –

+0

@ RichardJ.RossIII Zobacz zaktualizowane. :) –

3

Oto moja zmodyfikowana wersja kodu Jacoba. Miałem problemy z jego wersją, ponieważ metoda class_getMethodImplementation zwracała wartość _objc_msgForward, co powodowało, że metody były traktowane jako przesłonięte. Ja też nie trzeba * rootImpClass ale jest na tyle prosty, aby dodać widok.

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; 
} 
Powiązane problemy