是否可以使用Objective-C运行时功能来确定调用方法的位置?

时间:2009-07-12 02:17:44

标签: objective-c methods runtime introspection

当一个对象在另一个对象上调用方法时,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 个答案:

答案 0 :(得分:11)

不是运行时。所有消息发送最终都会在objc_msgSend(id receiver, SEL selector, /*method arguments*/...)的行中进行函数调用。如您所见,没有传递有关发送消息的对象的信息。通过遍历堆栈来确定调用对象可能是可能的,但这种方式就是疯狂。告诉谁调用该方法的唯一实用方法是给它一个sender参数,就像所有IBAction方法一样。

答案 1 :(得分:4)

我希望这会有所帮助:

    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 :(得分:2)

不,你无法确定叫你的对象。好吧,从技术上讲,它可能会在堆栈后面跟踪,但对于真正的代码来说肯定不实用。

如果查看大多数委托方法,可以看到标准委托调用格式如下所示:

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

注意窗口(调用者)如何作为第一个参数传递,以及“window”如何作为方法名称的第一部分。在最后一种情况下,窗口调用者隐含在NSNotification中(notification.object是窗口)。

答案 3 :(得分:2)

您可以尝试从NSInvocation派生自己的类,其中包含调用者信息。或者围绕NSInvocation包装一个类,重新实现那里的一些调用。