2009-07-12 17 views
6

Objective-C utilise un système sophistiqué de transmission de messages lorsqu'un objet appelle une méthode sur un autre objet. Je veux savoir s'il est possible, dans la méthode appelée, de déterminer quel était l'objet appelant?Est-il possible d'utiliser les fonctions d'exécution d'Objective-C pour déterminer l'origine d'une méthode?

Par exemple:

@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 

Que pouvais-je écrire dans la ligne commentée afin de faire passer l'assertion quand j'exécute performTest?

Répondre

11

Pas avec le temps d'exécution. Tous les messages envoyés aboutissent finalement à un appel de fonction suivant les lignes objc_msgSend(id receiver, SEL selector, /*method arguments*/...). Comme vous pouvez le voir, aucune information n'est transmise sur l'objet qui envoie le message. Il est probablement possible de déterminer l'objet appelant en marchant dans la pile, mais de cette façon, il y a de la folie. La seule façon pratique de dire qui a appelé la méthode est de lui donner un argument sender comme toutes les méthodes IBAction.

2

Non, vous ne pouvez pas déterminer quel objet vous a appelé. Eh bien, techniquement, il pourrait être possible de fouiller dans la trace de la pile, mais ce n'est certainement pas pratique pour le code réel.

Si vous regardez la plupart des méthodes de délégué, vous pouvez voir que les formats standard d'appel des délégués se présentent comme suit:

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

Remarque comment la fenêtre (l'appelant) est passé comme premier argument, et comment "window" est la première partie du nom de la méthode. Dans le dernier cas, l'appelant de la fenêtre est implicite dans le NSNotification (notification.object est la fenêtre).

2

Vous pouvez essayer de dériver votre propre classe de NSInvocation qui contient les informations de l'appelant. Ou enveloppez une classe autour de NSInvocation en réimplémentant certains des appels qui s'y trouvent.

+0

NSInvocation n'a également rien sur l'appelant - cible juste, sélecteur et arguments. –

+0

C'est pourquoi j'ai suggéré de dériver une nouvelle classe ou de l'enrouler, cela pourrait au moins vous donner un moyen cohérent de passer l'expéditeur dans la fonction appelante ou éventuellement de construire une structure de données où les informations peuvent être extraites. Cela dépend de ce qu'il essaie d'accomplir –

4

J'espère que cette aide:

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