我正在为客户开发一款iPad应用程序。有大量的工作已经完成,我正在努力拼凑整个设计的运行方式。
我想做的其中一件事是记录应用程序运行时调用哪些方法。我已经看到了一个自定义DTrace脚本,它意味着从启动时记录所有方法,但是当我在Instruments中运行它时,我没有得到任何结果。
记录方法的最佳方法是什么?
受到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
此外,我认为你会看到注销你的应用程序中调用的每个方法都会让你无法获得信息。您可以使用某些条件来过滤它,但我不知道这是否有助于您了解代码的执行方式。
NSLog(@"%@", NSStringFromSelector(_cmd));
要么
NSLog(@"%s", __PRETTY_FUNCTION__);
如果使用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))
要在设备上跟踪Xcode 6下的应用程序代码,我必须使用以下调试器表达式。
expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($arg1),$arg2)
可以使用调试器命令调整Brad Larson的方法以在设备上运行:
printf "[%s %s]\n", (char *)object_getClassName($r0),$r1
更多信息可以在技术说明中找到:technotes
以后需要像这样调用的xcode版本
expr -- (void)printf("[%s, %s]\n",(char *) object_getClassName(*(long*)($esp+4)), (char *) *(long *)($esp+8) )
如果要将输出限制为仅发送到一个类的消息,可以添加这样的条件
(int)strcmp((char *)object_getClassName($ r0),“NSString”)== 0
一位开发人员教我向每个方法添加相同的两个日志语句。一个作为第一行,另一个作为最后一行。我认为他有一个脚本可以自动为他的项目执行此操作,但结果是:
NSLog(@"<<< Entering %s >>>", __PRETTY_FUNCTION__);
NSLog(@"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
在控制台,这将吐出类似于:
<<< Entering -[MainListTableViewController viewDidLoad] >>>
非常有助于跟踪正在发生的事情。
适用于在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