2009-11-25 29 views
10

Ejemplo: Cuando se llama a mi método -fooBar, quiero que inicie sesión en la consola a qué otro método lo llamó otra clase.¿Cómo saber quién llamó a un método?

En este momento, lo único que saben cómo iniciar una sesión el nombre del método de sí mismo y de su clase FooBar, con esto:

_cmd 

[self class] 

Es esto posible averiguar?

Respuesta

36

En un código completamente optimizado, no hay una manera 100% segura de determinar quién llama a un método determinado. El compilador puede emplear una optimización de cola de llamada mientras que el compilador reutiliza eficazmente el marco de pila de la persona que llama para el destinatario.

Para ver un ejemplo de esto, establezca un punto de interrupción en cualquier método dado usando gdb y observe la traza inversa. Tenga en cuenta que no ve objc_msgSend() antes de cada llamada a un método. Eso es porque objc_msgSend() hace una llamada de cola a la implementación de cada método.

Si bien podría compilar su aplicación no optimizada, necesitaría versiones no optimizadas de todas las bibliotecas del sistema para evitar solo este problema.

Y esto es solo un problema; en efecto, usted está preguntando "¿cómo reinicio CrashTracer o gdb?". Un problema muy difícil sobre el cual se hacen carreras. A menos que desee que su "carrera profesional" sea una herramienta de depuración, recomendaría no seguir por este camino.

¿Qué pregunta estás tratando de responder?

+3

Esto es una respuesta negativa. –

+7

@alexgray ¿Cómo es una respuesta negativa?La respuesta es exactamente precisa en cuanto al alcance y la escala del problema y, dada la aceptación y la pregunta final, es de esperar que guíe a la OP por el camino hacia el éxito. – bbum

3

No es posible en el caso general sin caminar la pila. Ni siquiera hay una garantía de que otro objeto envíe el mensaje que llamó al método. Por ejemplo, podría llamarse desde un bloque en un manejador de señal.

1

Esta información se puede obtener utilizando DTrace.

1

Crea una macro que agrega __FUNCTION__ al nombre de la función a la llamada a la función. Esta macro llamará a su función con un parámetro adicional de char * a la función objetivo.

+0

eso supone que tiene control sobre la persona que llama y puede cambiar el ABI entre llamador y cal lee cambiando la argumentación, que rara vez es el caso. – bbum

6

¿Qué tal this:

NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1]; 

NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:@" -[]+?.,"]; 
NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString componentsSeparatedByCharactersInSet:separatorSet]]; 
[array removeObject:@""]; 

NSLog(@"Class caller = %@", [array objectAtIndex:3]); 
NSLog(@"Method caller = %@", [array objectAtIndex:4]); 

Créditos al autor original, intropedro.

+3

Eso no funcionará en un código completamente optimizado ya que las optimizaciones de cola de cola hacen que los marcos desaparezcan por completo de la pila. – bbum

2

usuario el siguiente método
índice de paso para el que desea mostrar método y pase -1 si desea mostrar completa pila de método

+(void) methodAtIndex:(int)index{ 
    void* callstack[128]; 
    int frames = backtrace(callstack, 128); 
    char** strs = backtrace_symbols(callstack, frames); 

    if (index == -1) { 
     for (int i = 0; i < frames; ++i) { 
      printf("%s\n", strs[i]); 
     } 
    } 
    else { 
     if (index < frames) { 
      printf("%s\n", strs[index]); 
     } 
    } 
    free(strs); 

} 
+0

Me sale 'error: advertencia: no se pudo obtener el puntero cmd (sustituyendo NULL): no se encontró ninguna variable llamada '_cmd' en este marco' – ReDetection

0

yo estaba tratando de atrapar a quién, cómo y cuándo cambia el tamaño de la ventana e hizo algunos trabajos manuales:

- (void)logWindowWidth:(NSString *)whoCalls { 
    NSLog(@"%@", whoCalls); 
    NSLog(@"self.window.size.width %f", self.window.size.width); 
} 

-(void)someMethod { 
    [self logWindowWidth:@"someMethod - before"]; 
    ... 
    [self logWindowWidth:@"someMethod - after"]; 
} 

-(void)anotherMethod { 
    [self logWindowWidth:@"anotherMethod - before"]; 
    ... 
    [self logWindowWidth:@"anotherMethod - after"]; 
} 
1
NSLog(@"Show stack trace: %@", [NSThread callStackSymbols]); 
Cuestiones relacionadas