我正在为客户开发一款iPad应用程序。有大量的工作已经完成,我正在努力拼凑整个事物的运行方式。
我想做的其中一件事是记录应用程序运行时调用哪些方法。我已经看到了一个自定义DTrace脚本,它意味着记录启动时的所有方法,但是当我在Instruments中运行它时,我没有得到任何结果。
记录方法的最佳方法是什么?
答案 0 :(得分:54)
受到tc对类似问题here的回答的启发,我整理了一个调试断点操作,该操作将在应用程序中每次触发objc_msgSend()时注销类和方法名称。这与我在this answer中描述的DTrace脚本类似。
要启用此断点操作,请创建一个新的符号断点(在Xcode 4中,转到断点导航器并使用窗口左下角的加号创建一个新的符号断点)。使符号为objc_msgSend
,将其设置为在评估操作后自动继续,并使用以下操作将操作设置为调试器命令:
printf "[%s %s]\n", (char *)object_getClassName(*(long*)($esp+4)),*(long *)($esp+8)
您的断点应如下所示:
这应该在针对您的应用程序运行时注销这样的消息:
[UIApplication sharedApplication]
[UIApplication _isClassic]
[NSCFString getCString:maxLength:encoding:]
[UIApplication class]
[SLSMoleculeAppDelegate isSubclassOfClass:]
[SLSMoleculeAppDelegate initialize]
如果您想知道我在何处提取内存地址,请阅读Objective-C运行时内部的this Phrack article。上面的内存地址只能用于模拟器,因此您可能需要调整它以针对iOS设备上的应用程序运行。 Collin建议在his answer中进行以下修改,以便在设备上运行:
printf "[%s %s]\n", (char *)object_getClassName($r0),$r1
另外,我认为您会看到注销应用程序中调用的每个方法都会让您感到不堪重负。您可能可以使用某些条件来过滤它,但我不知道这是否有助于您了解代码的执行方式。
答案 1 :(得分:17)
如果您使用的是LLDB,则需要使用以下调试器命令。这些在Xcode 4.6中进行了测试。
设备:强>
expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($r0),$r1)
<强>模拟器:强>
expr -- (void) printf("[%s %s]\n", (char *)object_getClassName(*(long*)($esp+4)), *(long *)($esp+8))
答案 2 :(得分:5)
要在设备上的Xcode 6下跟踪应用程序代码,我必须使用以下调试器表达式。
expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($arg1),$arg2)
答案 3 :(得分:4)
使用调试器命令可以调整Brad Larson的方法在设备上运行:
printf "[%s %s]\n", (char *)object_getClassName($r0),$r1
更多信息可在此处的技术说明中找到:technotes
答案 4 :(得分:3)
以后的xcode版本需要像那样调用
expr -- (void)printf("[%s, %s]\n",(char *) object_getClassName(*(long*)($esp+4)), (char *) *(long *)($esp+8) )
答案 5 :(得分:2)
如果要将输出限制为仅发送到一个类的消息,可以添加类似
的条件(int)strcmp((char *)object_getClassName($ r0),“NSString”)== 0
答案 6 :(得分:1)
一位开发人员教我向每个方法添加相同的两个日志语句。一个作为第一行,另一个作为最后一行。我认为他有一个脚本可以自动为他的项目执行此操作,但结果是:
NSLog(@"<<< Entering %s >>>", __PRETTY_FUNCTION__);
NSLog(@"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
在控制台上,这会吐出类似的东西:
<<< Entering -[MainListTableViewController viewDidLoad] >>>
非常有助于跟踪正在发生的事情。
答案 7 :(得分:1)
如果要在64位模拟器中记录方法,请改用以下命令:
expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($rdi), (char *) $rsi)
如果这不起作用,请以这种方式记录:
主要思想是使用$ rdi作为对象(self),使用$ rsi作为选择器。
答案 8 :(得分:0)
对于在Mac上以arm / x86_64体系结构流程运行的iOS simulator
应用
使用Symbolic Breakpoint
符号和下一个objc_msgSend
Debugger Command
p (void)printf("[%s, %s]\n", (char*)object_getClassName($arg1), $arg2)
p
是expr --
来源是SO answer
答案 9 :(得分:-1)
NSLog(@"%@", NSStringFromSelector(_cmd));
OR
NSLog(@"%s", __PRETTY_FUNCTION__);