【问题标题】:How to find out who called a method?如何找出谁调用了一个方法?
【发布时间】:2009-11-25 00:51:21
【问题描述】:

示例:当我的方法 -fooBar 被调用时,我希望它登录控制台,哪个其他类的哪个其他方法调用了它。

现在,我只知道如何记录 fooBar 本身的方法名称和它的类,用这个:

_cmd

[self class]

这可以解决吗?

【问题讨论】:

    标签: objective-c cocoa cocoa-touch


    【解决方案1】:

    在完全优化的代码中,没有 100% 可靠的方法来确定某个方法的调用者。编译器可以使用尾调用优化,而编译器有效地为被调用者重用调用者的堆栈帧。

    要查看此示例,请使用 gdb 在任何给定方法上设置断点并查看回溯。请注意,您不会在每次方法调用之前看到 objc_msgSend()。那是因为 objc_msgSend() 对每个方法的实现进行了尾调用。

    虽然您可以编译未优化的应用程序,但您需要所有系统库的未优化版本才能避免这一问题。

    这只是一个问题;实际上,您是在问“我如何重新发明 CrashTracer 或 gdb?”。一个非常困难的问题,职业生涯是在这个问题上产生的。除非您希望“调试工具”成为您的职业,否则我建议您不要走这条路。

    你真正想回答什么问题?

    【讨论】:

    • @alexgray 它是如何反答案的?答案在问题的范围和规模上非常精确,并且考虑到接受和最终问题,希望能引导 OP 走上成功之路。
    【解决方案2】:

    this怎么样:

    NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1];
    
    NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:@" -[]+?.,"];
    NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString  componentsSeparatedByCharactersInSet:separatorSet]];
    [array removeObject:@""];
    
    NSLog(@"Class caller = %@", [array objectAtIndex:3]);
    NSLog(@"Method caller = %@", [array objectAtIndex:4]);
    

    感谢原作者intropedro

    【讨论】:

    • 这在完全优化的代码中不起作用,因为尾调用优化会使帧完全从堆栈中消失。
    【解决方案3】:

    在一般情况下,如果不实际遍历堆栈,这是不可能的。甚至不能保证另一个对象会发送调用该方法的消息。例如,可以从信号处理程序中的块调用它。

    【讨论】:

      【解决方案4】:

      backtrace(3)

      【讨论】:

        【解决方案5】:

        使用以下方法
        传递要显示方法的索引,如果要显示方法的完整堆栈,则传递-1

        +(void) methodAtIndex:(int)index{
            void* callstack[128];
            int frames = backtrace(callstack, 128);
            char** strs = backtrace_symbols(callstack, frames);
        
            if (index == -1) {
                for (int i = 0; i < frames; ++i) {
                    printf("%s\n", strs[i]);
                }
            }
            else {
                if (index < frames) {
                    printf("%s\n", strs[index]);
                }
            }
            free(strs);
        
        }
        

        【讨论】:

        • 我收到error: warning: couldn't get cmd pointer (substituting NULL): no variable named '_cmd' found in this frame
        【解决方案6】:
        NSLog(@"Show stack trace: %@", [NSThread callStackSymbols]);
        

        【讨论】:

          【解决方案7】:

          可以使用DTrace获取此信息。

          【讨论】:

            【解决方案8】:

            制作一个宏,将__FUNCTION__ 添加到函数调用的函数名中。然后,此宏将使用 char* 的额外参数调用您的函数到目标函数。

            【讨论】:

            • 假设您可以控制调用者,并且可以通过更改参数来更改调用者和被调用者之间的 ABI,这种情况很少发生。
            【解决方案9】:

            我试图了解谁、如何以及何时更改窗口的大小并做了一些手工操作:

            - (void)logWindowWidth:(NSString *)whoCalls {
               NSLog(@"%@", whoCalls);
               NSLog(@"self.window.size.width %f", self.window.size.width);
            }
            
            -(void)someMethod {
              [self logWindowWidth:@"someMethod - before"];
              ...
              [self logWindowWidth:@"someMethod - after"];
            }
            
            -(void)anotherMethod {
              [self logWindowWidth:@"anotherMethod - before"];
              ...
              [self logWindowWidth:@"anotherMethod - after"];
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2022-10-24
              • 2014-01-09
              • 1970-01-01
              • 2013-09-30
              • 2017-06-24
              • 2015-01-05
              相关资源
              最近更新 更多