2009-07-12 5 views
6

Objective-C utiliza un sofisticado sistema de paso de mensajes cuando un objeto llama a un método en otro objeto. Quiero saber si es posible, dentro del método llamado, determinar cuál fue el objeto llamante.¿Es posible usar las características de tiempo de ejecución de Objective-C para determinar de dónde se llamó un método?

Por ejemplo:

@implementation callingClass 
- (void)performTest 
{ 
    calledObject = [[[calledClass alloc] init] autorelease]; 
    id result = [calledObject calledMethod]; 

    assert(result == this); 
} 
@end 

@implementation calledClass 
- (id)calledMethod 
{ 
    id objectThatCalledThisMethod = ... // <-- what goes here? 

    return objectThatCalledThisMethod; 
} 
@end 

¿Qué podría escribir en la línea comentada con el fin de hacer el pase afirmación cuando ejecuto performTest?

Respuesta

11

No con el tiempo de ejecución. Todos los mensajes enviados finalmente funcionan en una llamada de función a lo largo de las líneas objc_msgSend(id receiver, SEL selector, /*method arguments*/...). Como puede ver, no se pasa información sobre el objeto que envía el mensaje. Probablemente sea posible determinar el objeto que llama caminando sobre la pila, pero de esa manera se encuentra la locura. La única forma práctica de saber quién llamó al método es darle un argumento sender como todos los métodos de IBAction.

2

No, no puede determinar qué objeto lo llamó. Bueno, técnicamente, podría ser posible hurgar en la pila, pero ciertamente no es práctico para el código real.

Si nos fijamos en la mayoría de los métodos de delegado, se puede ver que los formatos de llamada delegado estándar se ven así:

- (NSSize) windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize; 
- (BOOL) windowShouldClose:(id)window; 
- (void) windowWillMove:(NSNotification *)notification; 

Nota cómo se pasa la ventana (el que llama) como primer argumento, y cómo "ventana" es la primera parte del nombre del método. En el último caso, el llamador de ventana está implícito en NSNotification (notification.object es la ventana).

2

Puede intentar derivar su propia clase de NSInvocation que transmita la información de la persona que llama. O envuelva una clase alrededor de NSInvocation para volver a implementar algunas de las llamadas allí.

+0

NSInvocation también no tiene nada acerca de la persona que llama - solo objetivo, el selector, y los argumentos. –

+0

Es por eso que sugerí derivar una nueva clase o ajustarla, al menos esto podría darle una forma consistente de pasar el remitente a la función de llamada o posiblemente construir una estructura de datos desde donde se pueda extraer la información en el extremo de los receptores. Depende de lo que intenta lograr –

4

espero que esto ayuda:

NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1]; 
    // Example: 1 UIKit        0x00540c89 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1163 
    NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:@" -[]+?.,"]; 
    NSMutableArray *array = [NSMutableArray arrayWithArray:[origen componentsSeparatedByCharactersInSet:separatorSet]]; 
    [array removeObject:@""]; 

    NSLog(@"Pila = %@", [array objectAtIndex:0]); 
    NSLog(@"Framework = %@", [array objectAtIndex:1]); 
    NSLog(@"Memory address = %@", [array objectAtIndex:2]); 
    NSLog(@"Class caller = %@", [array objectAtIndex:3]); 
    NSLog(@"Function caller = %@", [array objectAtIndex:4]); 
    NSLog(@"Line caller = %@", [array objectAtIndex:5]); 
Cuestiones relacionadas