2008-12-01 8 views

Odpowiedz

71

Jest to rozwiązanie oparte na funkcjach Runtime C:

class_copyMethodList zwraca listę metod klasy danego obiektu klasy otrzymać ze związku obiekt.

#import <objc/runtime.h> 

[..]

SomeClass * t = [[SomeClass alloc] init]; 

int i=0; 
unsigned int mc = 0; 
Method * mlist = class_copyMethodList(object_getClass(t), &mc); 
NSLog(@"%d methods", mc); 
for(i=0;i<mc;i++) 
    NSLog(@"Method no #%d: %s", i, sel_getName(method_getName(mlist[i]))); 

/* note mlist needs to be freed */ 
+8

Ta odpowiedź podaje metody klasy. Jeśli chcesz, aby metody, które obiekt zareagował, zastąpiły ten wiersz: 'Method * mlist = class_copyMethodList (object_getClass (t), &mc);' z tym jednym 'Method * mlist = class_copyMethodList (t, &mc);' – bugloaf

+1

@bugloaf jak twój komentarz ma sens ? sygnatura obiektu object_getClass oczekuje zmiennej klasy? – abbood

+0

@abbood Co nie rozumiesz mojego komentarza? Właśnie sprawdziłem teraz dokumentację i stoję za moim komentarzem. 'object_getClass' spodziewa się obiektu i zwraca klasę obiekt, którego argumentem jest instancja, jeśli 'class_copyMethodList' jest przekazywany obiekt klasy, zwróci metody klasy.Jeśli zostanie przekazany zwykły obiekt, zwróci metody na ten obiekt: – bugloaf

1

Coś takiego powinno zadziałać (wystarczy umieścić go w obiekcie, który nas interesuje). Na przykład, jeśli masz obiekt, który jest delegatem i chcą wiedzieć, jakie są dostępne „haki” to będzie wydrukować wiadomości daje, że pojęcia:

-(BOOL) respondsToSelector:(SEL)aSelector { 
    printf("Selector: %s\n", [NSStringFromSelector(aSelector) UTF8String]); 
    return [super respondsToSelector:aSelector]; 
} 

pamiętać, że odkrył to w iPhone programisty Cookbook więc nie mogę wziąć kredytu! Na przykład wyjście otrzymuję od UIViewController który implementuje protokoły <UITableViewDelegate, UITableViewDataSource>:

Selector: tableView:numberOfRowsInSection: 
Selector: tableView:cellForRowAtIndexPath: 
Selector: numberOfSectionsInTableView: 
Selector: tableView:titleForHeaderInSection: 
Selector: tableView:titleForFooterInSection: 
Selector: tableView:commitEditingStyle:forRowAtIndexPath: 
Selector: sectionIndexTitlesForTableView: 
Selector: tableView:sectionForSectionIndexTitle:atIndex: 
... 
... 
etc.,etc. 
+0

AFAICS nie jive. Skąd pochodzą te argumenty? – nmr

+2

To będzie tylko lista selektorów, które są dynamicznie sprawdzane w czasie wykonywania (tak jak w "nieformalnych protokołach" Objective-C), nie wszystkie selektory, na które reaguje obiekt. – rvalue

25

myślę zazwyczaj będziemy chcieli to zrobić w konsoli zamiast zaśmiecania kod z debugowania kodu. W ten sposób można to zrobić podczas debugowania w lldb:

(Zakładając, że obiekt t)

p int $num = 0; 
expr Method *$m = (Method *)class_copyMethodList((Class)object_getClass(t), &$num); 
expr for(int i=0;i<$num;i++) { (void)NSLog(@"%s",(char *)sel_getName((SEL)method_getName($m[i]))); } 
3

Jest to również możliwe w przypadku Swifta:

let obj = NSObject() 

var mc: UInt32 = 0 
let mcPointer = withUnsafeMutablePointer(&mc, { $0 }) 
let mlist = class_copyMethodList(object_getClass(obj), mcPointer) 

print("\(mc) methods") 

for i in 0...Int(mc) { 
    print(String(format: "Method #%d: %s", arguments: [i, sel_getName(method_getName(mlist[i]))])) 
} 

wyjściowa:

251 methods 
Method #0: hashValue 
Method #1: postNotificationWithDescription: 
Method #2: okToNotifyFromThisThread 
Method #3: fromNotifySafeThreadPerformSelector:withObject: 
Method #4: allowSafePerformSelector 
Method #5: disallowSafePerformSelector 
... 
Method #247: isProxy 
Method #248: isMemberOfClass: 
Method #249: superclass 
Method #250: isFault 
Method #251: <null selector> 

Testowany za pomocą symulatora 6s z systemem iOS 9.2, Xcode w wersji 7.2 (7C68).

0

wzorując odpowiedź JAL „s, w Swift można zrobić:

extension NSObject { 
    var __methods: [Selector] { 
     var methodCount: UInt32 = 0 
     guard 
      let methodList = class_copyMethodList(type(of: self), &methodCount), 
      methodCount != 0 
     else { return [] } 
     return (0 ..< Int(methodCount)) 
      .flatMap({ method_getName(methodList[$0]) }) 
    } 
}