Можно ли использовать функции времени выполнения Objective C, чтобы определить, откуда был вызван метод? - PullRequest
6 голосов
/ 12 июля 2009

Objective-C использует сложную систему передачи сообщений, когда один объект вызывает метод для другого объекта. Я хочу знать, возможно ли в вызываемом методе определить, каким был вызывающий объект?

Например:

@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

Что я мог бы написать в закомментированной строке, чтобы утверждение прошло, когда я выполню performTest?

Ответы [ 4 ]

11 голосов
/ 12 июля 2009

Не во время выполнения. В конечном итоге все сообщения отправляются на вызов функции по типу objc_msgSend(id receiver, SEL selector, /*method arguments*/...). Как видите, информация об объекте, отправляющем сообщение, не передается. Вероятно, можно определить вызывающий объект, пройдя по стеку, но в этом и заключается безумие. Единственный практический способ определить, кто вызвал метод, - это задать ему аргумент sender, как все методы IBAction.

4 голосов
/ 07 марта 2012

Я надеюсь, что это поможет:

    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]);
2 голосов
/ 12 июля 2009

Вы можете попытаться получить свой собственный класс из NSInvocation, который содержит информацию о вызывающем абоненте. Или оберните класс вокруг NSInvocation, реализуя некоторые вызовы там.

2 голосов
/ 12 июля 2009

Нет, вы не можете определить, какой объект вызвал вас. Ну, технически, возможно, можно обойти обратную трассировку стека, но, конечно, это не практично для реального кода.

Если вы посмотрите на большинство методов делегата, вы увидите, что стандартные форматы вызова делегата выглядят так:

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

Обратите внимание, как окно (вызывающая сторона) передается в качестве первого аргумента, и как «окно» является первой частью имени метода. В последнем случае оконный абонент неявно присутствует в NSNotification (уведомлением является объект окна).

...