2013-04-09 22 views
8

Sınıf hiyerarşisinde nerede class_getInstanceMethod tarafından alınan yöntem nereden geliyor bulmak mümkün mü? Örneğin, A Sınıfı myMethod uygular. Şimdi, Sınıf A’de Sınıf A’yı alt sınıflara ayırdığımı söyle. class_getInstanceMethod(ClassA1, myMethod)'u ararsam, sonuçta ortaya çıkan yöntemin ClassA1'de geçersiz kılındığını veya doğrudan A1'den mi geldiğini söylemek mümkün müdür?class_getInstanceMethod öğesini kullanma - yöntem sınıf hiyerarşisinde nerede uygulanır?

Sana ClassA ve ClassA1 hem erişim olsaydı araştırma ürünlerinin bellek adreslerini karşılaştırmak mümkün olacaktır herhalde, ama ben

cevap

15

Hep bir sınıf erişebilirler A. doğrudan erişim yok superclass, böylece class_getInstanceMethod veya class_getMethodImplementation ile aynı SEL ile geçirebilir ve yöntemin alt sınıf tarafından geçersiz kılındığını görmek için IMP adreslerini karşılaştırabilirsiniz.

Bu yöntemi tanımlayan kök sınıfına ulaşmak istiyorsanız, bu biraz daha zor olur.

Neyse, buraya:

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

bu tür NSProxy' 'olarak' NSObject' değil alt nesneler için oluşturulacak başarısız olur –

+0

Bu müthiş. Sadece bir not. –

+0

@ RichardJ.RossIII Güncelleme. :) –

3

İşte Jacob kodunun benim değiştirilmiş versiyonu. Onunla ilgili problemlerim vardı çünkü class_getMethodImplementation yöntemi, yöntemlerin geçersiz kılınmasına neden olan bir _objc_msgForward döndürüyordu. Ayrıca * rootImpClass gerek yoktu ama geri eklemek için yeterli basit.

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