2009-07-12 4 views
6

Objective-C utilizza un sofisticato sistema di passaggio di messaggi quando un oggetto chiama un metodo su un altro oggetto. Voglio sapere se è possibile, all'interno del metodo chiamato, determinare quale fosse l'oggetto chiamante?È possibile utilizzare le funzioni di runtime Objective-C per determinare da dove è stato chiamato un metodo?

Ad esempio:

@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 

Quello che ho potuto scrivere nella linea commentata in modo da rendere il passaggio asserzione quando eseguo performTest?

risposta

11

Non con il runtime. Alla fine, tutti i messaggi arrivano a una chiamata di funzione lungo le linee objc_msgSend(id receiver, SEL selector, /*method arguments*/...). Come puoi vedere, nessuna informazione viene passata sull'oggetto che invia il messaggio. Probabilmente è possibile determinare l'oggetto chiamante camminando nello stack, ma in questo modo giace la follia. L'unico modo pratico per dire chi ha chiamato il metodo è dargli un argomento sender come tutti i metodi IBAction.

2

No, non è possibile determinare quale oggetto si chiama. Beh, tecnicamente, potrebbe essere possibile attirare l'attenzione sulla traccia di ritorno, ma certamente non è pratico per il codice reale.

Se si guarda alla maggior parte dei metodi delegati, si può vedere che i formati di chiamata delegato standard di simile a questa:

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

Si noti come la finestra (chiamante) viene passato come primo argomento, e come "window" è la prima parte del nome del metodo. Nell'ultimo caso, il chiamante della finestra è implicito in NSNotification (notification.object è la finestra).

2

È possibile provare e derivare la propria classe da NSInvocation che contiene le informazioni sul chiamante. In alternativa, avvolgi una classe attorno a NSInvocation che reimplementa alcune delle chiamate presenti.

+0

NSInvocation, inoltre, non ha nulla sul chiamante - solo obiettivo, selettore, e gli argomenti. –

+0

Ecco perché ho suggerito di derivare una nuova classe o di avvolgerla, questo potrebbe almeno darti un modo consistente per passare il mittente nella funzione chiamante o possibilmente costruire una struttura dati in cui le informazioni possono essere estratte dal destinatario. Dipende da ciò che sta cercando di realizzare –

4

spero che questo aiuta:

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