2013-04-09 5 views
8

Ist es möglich zu finden, wo in einer Klassenhierarchie die von class_getInstanceMethod abgerufene Methode herkommt? Angenommen, Klasse A implementiert myMethod. Jetzt sagen, ich habe Klasse A in Klasse A1 subclassed. Wenn ich class_getInstanceMethod(ClassA1, myMethod) aufrufen, ist es möglich zu sagen, ob die resultierende Methode in ClassA1 überschrieben wurde oder direkt von A1 kommt?Verwenden von class_getInstanceMethod - wo ist die Methode in der Klassenhierarchie implementiert?

Ich nehme an, es möglich wäre, die Speicheradressen der IMPs zu vergleichen, wenn Sie Zugang zu beiden KlasseA und ClassA1 haben, aber ich habe keinen direkten Zugriff auf A.

Antwort

15

Sie können immer eine Klasse zugreifen Superklasse, so können Sie es mit class_getInstanceMethod oder class_getMethodImplementation mit dem gleichen SEL übergeben und vergleichen Sie die IMP Adressen, um zu sehen, ob die Methode von der Unterklasse überschrieben wurde.

Dies wird ein bisschen haariger, wenn Sie an die Wurzelklasse gelangen wollen, die diese Methode definiert.

Wie auch immer, hier geht:

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

dies für Objekte Dieser –

+0

fehl genial, die Unterklasse nicht 'NSObject', wie' NSProxy'. Nur eine Notiz. –

+0

@ RichardJ.RossIII Siehe aktualisiert. :) –

3

meine modifizierte Version hier Jakobs-Code. Ich hatte Probleme mit seinem, weil class_getMethodImplementation einen _objc_msgForward zurückgab, der dazu führte, dass Methoden als überschrieben behandelt wurden. Ich brauche auch nicht * rootImpClass aber es ist einfach genug, um wieder hinzufügen.

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