2009-11-25 5 views
10

Exemple: Quand ma méthode -fooBar est appelée, je veux qu'elle se connecte à la console quelle autre méthode l'a appelée.Comment savoir qui a appelé une méthode?

En ce moment, je ne sais pas comment se connecter le nom de la méthode de fooBar lui-même et sa classe, avec ceci:

_cmd 

[self class] 

Est-ce possible de comprendre?

Répondre

36

Dans un code entièrement optimisé, il n'existe aucun moyen fiable à 100% de déterminer l'appelant pour une certaine méthode. Le compilateur peut utiliser une optimisation d'appel de queue alors que le compilateur réutilise effectivement la trame de pile de l'appelant pour l'appelé.

Pour voir un exemple de ceci, définissez un point d'arrêt sur une méthode donnée en utilisant gdb et regardez le backtrace. Notez que vous ne voyez pas objc_msgSend() avant chaque appel de méthode. C'est parce que objc_msgSend() fait un appel de queue à l'implémentation de chaque méthode.

Bien que vous puissiez compiler votre application non optimisée, vous auriez besoin de versions non optimisées de toutes les bibliothèques système pour éviter ce problème.

Et c'est juste un problème; en effet, vous demandez "comment puis-je réinventer CrashTracer ou gdb?". Un problème très difficile sur lequel les carrières sont faites. À moins que vous ne vouliez que les «outils de débogage» soient votre carrière, je recommanderais de ne pas aller dans cette direction.

À quelle question tentez-vous vraiment de répondre?

+3

Ceci est un anti-réponse. –

+7

@alexgray Comment est-ce un anti-réponse?La réponse est exactement précise quant à la portée et à l'ampleur du problème et, compte tenu de l'acceptation et de la question finale, nous espérons que le PO sera sur la voie du succès. – bbum

3

Ce n'est pas possible dans le cas général sans réellement marcher sur la pile. Il n'y a même pas de garantie qu'un autre objet envoie le message qui a appelé la méthode. Par exemple, il pourrait être appelé à partir d'un bloc dans un gestionnaire de signal.

1

Cette information peut être obtenue en utilisant DTrace.

1

Créez une macro qui ajoute __FUNCTION__ au nom de la fonction à l'appel de fonction. Cette macro appellera alors votre fonction avec un paramètre supplémentaire de char * à la fonction cible.

+0

cela suppose que vous avez le contrôle sur l'appelant et peut changer l'ABI entre l'appelant et cal Lee en changeant l'argumentation, ce qui est rarement le cas. – bbum

6

Que diriez-vous 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édits à l'auteur original, intropedro.

+3

Cela ne fonctionnera pas dans un code entièrement optimisé, car les optimisations de la fin de l'appel font disparaître complètement les images de la pile. – bbum

2

utilisateur la méthode ci-dessous
index Pass pour lequel vous souhaitez afficher la méthode et passer -1 si vous voulez afficher la pile complète de la méthode

+(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

Je reçois 'error: avertissement: impossible d'obtenir cmd pointeur (en remplaçant NULL): aucune variable nommée '_cmd' trouvée dans cette image' – ReDetection

0

je tentais d'attraper qui, comment et quand la taille de la fenêtre des changements et a fait des travaux manuels:

- (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]); 
Questions connexes