2008-12-01 4 views

Respuesta

71

Esta es una solución basada en las funciones de tiempo de ejecución C:

class_copyMethodList devuelve una lista de métodos de clase dado un objeto de clase que se puede obtener a partir de una objeto.

#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

Esta respuesta le proporciona los métodos de clase. Si desea los métodos a los que responde el objeto, reemplace esta línea 'Método * mlist = class_copyMethodList (object_getClass (t), &mc);' con este 'Método * mlist = class_copyMethodList (t, &mc);' – bugloaf

+1

@bugloaf ¿Cómo tiene sentido su comentario? ? la firma de object_getClass espera una variable de clase? – abbood

+0

@abbood ¿Qué no entiendes de mi comentario? Acabo de volver a verificar la documentación y acepto mi comentario. 'object_getClass' espera un objeto y devuelve la clase objeto, cuyo argumento es una instancia. Si 'class_copyMethodList' se pasa un objeto de clase, devolverá los métodos de clase. Si se pasa un objeto normal, devolverá los métodos en ese objeto. – bugloaf

1

Algo así debería funcionar (simplemente colóquelo en el objeto que le interesa). Por ejemplo, si tiene un objeto que es un delegado y desea saber qué servicios están disponibles 'ganchos' esto va a imprimir los mensajes para que te de pista:

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

Tenga en cuenta que descubrí esto en Cookbook del iPhone desarrollador ¡así que no puedo tomar el crédito! Por ejemplo salida que recibo de un UIViewController que implementa los protocolos <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 esto no jive. ¿De dónde se supone que provienen los argumentos? – nmr

+2

Esto solo mostrará una lista de los selectores dinámicamente consultados en tiempo de ejecución (como con Objective-C "protocolos informales"), no todos los selectores a los que responde el objeto. – rvalue

25

creo que por lo general usted querrá hacer eso en la consola, en lugar de estorbar su código con el código de depuración. Así es como se puede hacer eso durante la depuración en LLDB:

(Suponiendo un objeto 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

Esto también es posible con Swift:

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]))])) 
} 

Salida:

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> 

Probado con el simulador 6s con iOS 9.2, Xcode Versión 7.2 (7C68).

0

Inspirándose en respuesta JAL 's, en Swift que puede hacer:

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]) }) 
    } 
} 
Cuestiones relacionadas