2009-07-12 9 views
6

Objective-C verwendet ein ausgeklügeltes Nachrichtenübergabesystem, wenn ein Objekt eine Methode für ein anderes Objekt aufruft. Ich möchte wissen, ob es innerhalb der aufgerufenen Methode möglich ist zu bestimmen, was das aufrufende Objekt war?Ist es möglich, mithilfe von Objective-C-Laufzeitfunktionen zu bestimmen, woher eine Methode aufgerufen wurde?

Zum Beispiel:

@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 

Was könnte ich in der Kommentarzeile schreiben, um die Behauptung Pass zu machen, wenn ich performTest ausführen?

Antwort

11

Nicht mit der Laufzeit. Alle Nachrichten senden schließlich zu einem Funktionsaufruf in den Zeilen objc_msgSend(id receiver, SEL selector, /*method arguments*/...). Wie Sie sehen, werden keine Informationen über das Objekt gesendet, das die Nachricht sendet. Es ist wahrscheinlich möglich, das aufrufende Objekt durch Gehen des Stapels zu bestimmen, aber auf diese Weise liegt der Wahnsinn. Der einzige praktische Weg zu sagen, wer die Methode aufgerufen hat, ist ein sender Argument, wie es alle IBAction-Methoden haben.

2

Nein, Sie können nicht bestimmen, welches Objekt Sie angerufen hat. Nun, technisch könnte es möglich sein, die Stack-Back-Spur zu durchsuchen, aber sicherlich nicht für echten Code.

Wenn Sie an den meisten der Delegatmethoden anschaut, kann man sehen, dass die Standard-Delegat Anruf-Formate wie folgt aussehen:

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

Beachten Sie, wie das Fenster (Anrufer) als erstes Argument übergeben wird, und wie "window" ist der erste Teil des Methodennamens. Im letzten Fall ist der Fensteraufruf implizit in der NSNotification (notification.object ist das Fenster).

2

Sie könnten versuchen, Ihre eigene Klasse von NSInvocation abzuleiten, die die Anruferinformationen enthält. Oder wickeln Sie eine Klasse um NSInvocation, um einige der dort eingehenden Aufrufe neu zu implementieren.

+0

NSInvocation auch nichts hat, über den Anrufer - nur Ziel, Wähler und Argumente. –

+0

Aus diesem Grund schlug ich vor, eine neue Klasse zu erstellen oder zu umschließen. Dies könnte Ihnen zumindest eine konsistente Möglichkeit geben, den Absender an die aufrufende Funktion zu übergeben oder eine Datenstruktur aufzubauen, von der die Informationen auf der Empfängerseite abgerufen werden können. Es hängt davon ab, was er zu erreichen versucht –

4

Ich hoffe, dass dies hilft:

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