如何logging在iOS应用程序中使用的所有方法
我正在接pipe客户端的iPad应用程序的开发。 有大量的工作已经完成,我正在试图拼凑整个事情是如何运行的。
我想要做的事情之一是logging当应用程序运行时调用哪些方法。 我见过一个自定义的DTrace脚本,意在logging启动时的所有方法,但是当我在Instruments中运行它时,我没有得到任何结果。
logging这些方法的最好方法是什么?
受到tc对类似问题的回答的启发,我将一个debugging断点操作放在一起,每次在应用程序中触发objc_msgSend()时,都会注销类和方法名称。 这与我在这个答案中描述的DTrace脚本类似。
要启用此断点操作,请创build一个新的符号断点(在Xcode 4中,转到断点导航器,并使用窗口左下angular的加号创build一个新的符号断点)。 将符号设置为objc_msgSend
,将其设置为在评估操作后自动继续,并使用以下命令将操作设置为debugging器命令:
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运行时内部的Phrack文章 。 上面的内存地址只对Simulator有效,所以你可能需要调整这个设置才能在iOS设备上运行。 Collin在他的答案中提出了以下修改,以便在设备上运行:
printf "[%s %s]\n", (char *)object_getClassName($r0),$r1
另外,我想你会发现注销应用程序中调用的每个方法都会使信息压倒你。 您可能可以使用一些条件来过滤,但是我不知道这是否会帮助您了解您的代码执行情况。
如果您使用LLDB,则需要使用以下debugging器命令。 这些在Xcode 4.6中进行了testing。
设备:
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))
Brad Larson的方法可以通过使用debugging器命令来适应在设备上运行:
printf "[%s %s]\n", (char *)object_getClassName($r0),$r1
更多信息可以在技术说明中find: 技术说明
要跟踪设备上的Xcode 6下的应用程序代码,我必须使用以下debugging器expression式。
expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($arg1),$arg2)
后来的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] >>>
跟踪正在发生的事情非常有帮助。
如果您想要在64位模拟器中logging方法,请改用以下命令:
expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($rdi), (char *) $rsi)
或者如果这不起作用,请按照以下方式logging:
主要思想是使用$ rdi作为对象(self),$ rsi作为select器。
NSLog(@"%@", NSStringFromSelector(_cmd));
要么
NSLog(@"%s", __PRETTY_FUNCTION__);