目标C找到方法的调用者

enn*_*ler 88 debugging objective-c nsthread ios

有没有办法确定某个特定的代码行method

int*_*dro 184

StackI希望这有助于:

    NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1];
    // Example: 1   UIKit                               0x00540c89 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1163
    NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:@" -[]+?.,"];
    NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString  componentsSeparatedByCharactersInSet:separatorSet]];
    [array removeObject:@""];

    NSLog(@"Stack = %@", [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]);
Run Code Online (Sandbox Code Playgroud)

  • 在我的情况下,索引5没有任何内容.因此,此代码崩溃了我的应用程序.删除最后一行后它工作.尽管如此,它仍然非常棒,值得+1! (4认同)
  • 它在调试模式下工作,但将其归档到 IPA 包后,调用堆栈未按预期工作。我刚刚得到“callStackSymbols = 1 SimpleApp 0x00000001002637a4 _Z8isxdigiti + 63136”,“_Z8isxdigiti”应该是“AAMAgentAppDelegate application:didFinishLaunchingWithOptions:” (2认同)

bbu*_*bum 50

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

要查看此示例,请使用gdb在任何给定方法上设置断点,然后查看回溯.请注意,在每次方法调用之前都没有看到objc_msgSend().这是因为objc_msgSend()对每个方法的实现进行尾调用.

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

这只是一个问题; 实际上,你问"我如何重新发明CrashTracer或gdb?".一个非常难以解决的职业问题.除非你想要"调试工具"成为你的职业,否则我建议不要走这条路.

你真的想回答什么问题?

  • 哦,我的上帝.这让我回到了地球.差不多字面上.我正在解决一个完全无关的问题.谢谢你,先生! (3认同)

Gun*_*nds 11

使用intropedro提供的答案,我想出了这个:

#define CALL_ORIGIN NSLog(@"Origin: [%@]", [[[[NSThread callStackSymbols] objectAtIndex:1] componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"[]"]] objectAtIndex:1])
Run Code Online (Sandbox Code Playgroud)

这将简单地返回原始类和功能:

2014-02-04 16:49:25.384 testApp[29042:70b] Origin: [LCallView addDataToMapView]
Run Code Online (Sandbox Code Playgroud)

ps - 如果使用performSelector调用函数,结果将是:

Origin: [NSObject performSelector:withObject:]
Run Code Online (Sandbox Code Playgroud)

  • *但请注意,在某些情况下,它不包含函数名称,也不执行选择器,因此 - 调用CALL_ORIGIN崩溃.(所以,我建议 - 如果你要使用这个例子,暂时使用它然后删除它.) (2认同)

Roy*_*y K 6

刚写了一个方法来为你做这个:

- (NSString *)getCallerStackSymbol {

    NSString *callerStackSymbol = @"Could not track caller stack symbol";

    NSArray *stackSymbols = [NSThread callStackSymbols];
    if(stackSymbols.count >= 2) {
        callerStackSymbol = [stackSymbols objectAtIndex:2];
        if(callerStackSymbol) {
            NSMutableArray *callerStackSymbolDetailsArr = [[NSMutableArray alloc] initWithArray:[callerStackSymbol componentsSeparatedByString:@" "]];
            NSUInteger callerStackSymbolIndex = callerStackSymbolDetailsArr.count - 3;
            if (callerStackSymbolDetailsArr.count > callerStackSymbolIndex && [callerStackSymbolDetailsArr objectAtIndex:callerStackSymbolIndex]) {
                callerStackSymbol = [callerStackSymbolDetailsArr objectAtIndex:callerStackSymbolIndex];
                callerStackSymbol = [callerStackSymbol stringByReplacingOccurrencesOfString:@"]" withString:@""];
            }
        }
    }

    return callerStackSymbol;
}
Run Code Online (Sandbox Code Playgroud)


Geo*_*f H 6

Swift 2.0版@Intropedro的答案供参考;

let sourceString: String = NSThread.callStackSymbols()[1]

let separatorSet :NSCharacterSet = NSCharacterSet(charactersInString: " -[]+?.,")
let array = NSMutableArray(array: sourceString.componentsSeparatedByCharactersInSet(separatorSet))
array.removeObject("")

print("Stack: \(array[0])")
print("Framework:\(array[1])")
print("Memory Address:\(array[2])")
print("Class Caller:\(array[3])")
print("Method Caller:\(array[4])")
Run Code Online (Sandbox Code Playgroud)


Gio*_*nni 5

如果是为了补偿缘故,那就养成放弃的习惯 NSLog(@"%s", __FUNCTION__);

作为类中每个方法的第一行.然后,您始终可以通过查看调试器来了解方法调用的顺序.

  • 或者更好地使用\ _ _ _ PRETTY_FUNCTION\_ _ _,它也支持Objective-C并显示对象名和方法. (3认同)