2013-04-09 38 views
8

Có thể tìm thấy vị trí trong phân cấp lớp mà phương thức được truy xuất bởi class_getInstanceMethod đến từ đâu không? Ví dụ, nói Class A thực hiện myMethod. Bây giờ nói rằng tôi đã phân loại lớp A trong lớp A1. Nếu tôi gọi class_getInstanceMethod(ClassA1, myMethod), có thể cho biết liệu phương pháp kết quả đã bị ghi đè trong ClassA1 hoặc trực tiếp từ A1 không?Sử dụng class_getInstanceMethod - phương thức được triển khai trong hệ thống phân cấp lớp ở đâu?

Tôi cho rằng nó sẽ có thể để so sánh các địa chỉ bộ nhớ của IMP nếu bạn có quyền truy cập vào cả hai ClassA và ClassA1, nhưng tôi không có quyền truy cập trực tiếp đến A.

Trả lời

15

Bạn luôn có thể truy cập vào một lớp học siêu lớp, vì vậy bạn có thể vượt qua nó theo số class_getInstanceMethod hoặc class_getMethodImplementation với cùng một số SEL và so sánh địa chỉ IMP để xem liệu phương pháp có bị ghi đè bởi lớp con hay không.

Điều này sẽ trở thành một phần nhỏ hơn nếu bạn muốn truy cập vào lớp gốc xác định phương thức này.

Dù sao, ở đây đi:

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

này là tuyệt vời –

+0

này sẽ thất bại cho các đối tượng mà không phân lớp 'NSObject', chẳng hạn như' NSProxy'. Chỉ cần một lưu ý. –

+0

@ RichardJ.RossIII Xem cập nhật. :) –

3

Dưới đây là phiên bản sửa đổi của tôi mã Jacob. Tôi đã có vấn đề với mình bởi vì class_getMethodImplementation đã trả về một _objc_msgForward đã gây ra các phương thức được coi là ghi đè. Tôi cũng không cần * rootImpClass nhưng nó đủ đơn giản để thêm lại.

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; 
} 
Các vấn đề liên quan