2009-07-12 10 views
6

Objective-C używa wyrafinowanego systemu przekazywania komunikatów, gdy jeden obiekt wywołuje metodę na innym obiekcie. Chcę wiedzieć, czy możliwe jest, w ramach wywoływanej metody, określenie, czym był obiekt wywołujący?Czy można użyć funkcji środowiska wykonawczego Objective-C do określenia, skąd została wywołana metoda?

Na przykład:

@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 

Co mogę napisać w komentowanej linii w celu uczynienia przepustkę twierdzenie kiedy wykonać performTest?

Odpowiedz

11

Nie w środowisku wykonawczym. Wszystkie wiadomości wysyłają ostatecznie do wywołania funkcji zgodnie z objc_msgSend(id receiver, SEL selector, /*method arguments*/...). Jak widać, nie przekazano żadnych informacji o obiekcie wysyłającym wiadomość. Prawdopodobnie możliwe jest określenie obiektu wywołującego przez chodzenie po stosie, ale w ten sposób leży szaleństwo. Jedynym praktycznym sposobem poinformowania się, kto wywołał tę metodę, jest przekazanie jej argumentu, jak wszystkie metody IBAction.

2

Nie, nie można ustalić, który obiekt się nazywał. No cóż, technicznie możliwe jest przesuwanie się po śladach stosu, ale z pewnością nie jest to praktyczne w przypadku prawdziwego kodu.

Jeśli spojrzeć na większość metod delegata widać, że standardowe formaty połączeń delegat wyglądać następująco:

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

Uwaga jak okno (rozmówcy) jest przekazywany jako pierwszy argument i jak "okno" jest pierwszą częścią nazwy metody. W ostatnim przypadku wywoływacz okna jest niejawny w NSNotification (notification.object jest oknem).

2

Możesz wypróbować własną klasę od NSInvocation, która przenosi informacje o dzwoniącym. Lub zawiń klasę wokół NSInvocation reimplementing niektórych połączeń tam.

+0

NSInvocation również nie ma nic o rozmówcy - tylko cel, selektora i argumentów. –

+0

Dlatego zaproponowałem wyprowadzenie nowej klasy lub owijanie jej wokół, to może przynajmniej dać ci spójny sposób przekazania nadawcy do funkcji wywołującej lub ewentualnie skonstruowania struktury danych, w której informacje mogą zostać wyciągnięte od końca odbiorcy. To zależy od tego, co stara się osiągnąć –

4

Mam nadzieję, że to pomaga:

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]); 
Powiązane problemy