Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/94.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 如何记录iOS应用程序中使用的所有方法_Iphone_Ios_Ipad_Instruments - Fatal编程技术网

Iphone 如何记录iOS应用程序中使用的所有方法

Iphone 如何记录iOS应用程序中使用的所有方法,iphone,ios,ipad,instruments,Iphone,Ios,Ipad,Instruments,我正在为一个客户开发iPad应用程序。已经做了大量的工作,我正试图拼凑出整个设计的运行方式 我想做的一件事是记录应用程序运行时调用的方法。我看到了一个定制的DTrace脚本,该脚本用于记录启动时的所有方法,但当我在工具中运行它时,并没有得到任何结果 记录方法的最佳方式是什么?一位开发人员教我在每个方法中添加相同的两条日志语句。一个作为第一行,另一个作为最后一行。我认为他有一个脚本,可以为他的项目自动执行此操作,但结果是: NSLog(@"<<< Entering %s >

我正在为一个客户开发iPad应用程序。已经做了大量的工作,我正试图拼凑出整个设计的运行方式

我想做的一件事是记录应用程序运行时调用的方法。我看到了一个定制的DTrace脚本,该脚本用于记录启动时的所有方法,但当我在工具中运行它时,并没有得到任何结果


记录方法的最佳方式是什么?

一位开发人员教我在每个方法中添加相同的两条日志语句。一个作为第一行,另一个作为最后一行。我认为他有一个脚本,可以为他的项目自动执行此操作,但结果是:

NSLog(@"<<< Entering %s >>>", __PRETTY_FUNCTION__);
NSLog(@"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
NSLog(@“>”,\uuu PRETTY\u FUNCTION\uuuuu);
NSLog(@“>”,uuu PRETTY_ufunction_uuu);
在控制台上,这将显示如下内容:

 <<< Entering -[MainListTableViewController viewDidLoad] >>>
>

非常有助于跟踪正在发生的事情。

受tc对一个类似问题的回答的启发,我设置了一个调试断点操作,每次在应用程序中触发objc_msgSend()时,该操作都将注销类和方法名。这与我在中描述的DTrace脚本类似

要启用此断点操作,请创建一个新的符号断点(在Xcode 4中,转到断点导航器并使用窗口左下角的加号创建一个新的符号断点)。将符号设置为objc\u msgSend,将其设置为在评估操作后自动继续,并使用以下命令将操作设置为调试器命令:

printf "[%s %s]\n", (char *)object_getClassName(*(long*)($esp+4)),*(long *)($esp+8)
您的断点应该如下所示:

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运行时内部。上面的内存地址只能在模拟器上运行,因此您可能需要调整它以在iOS设备上运行应用程序。Collin建议在中进行以下修改,以便在设备上运行此功能:

printf "[%s %s]\n", (char *)object_getClassName($r0),$r1

另外,我认为您会看到,注销应用程序中调用的每个方法都会让您感到信息泛滥。您可能可以使用一些条件来过滤此内容,但我不知道这是否有助于您了解代码的执行方式。

Brad Larson的方法可以通过使用debugger命令进行调整,以在设备上运行:

printf "[%s %s]\n", (char *)object_getClassName($r0),$r1

更多信息可以在这里的技术说明中找到:

以后的xcode版本需要这样调用

expr -- (void)printf("[%s, %s]\n",(char *) object_getClassName(*(long*)($esp+4)), (char *) *(long *)($esp+8) )

如果您使用的是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))
模拟器:

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))

如果要将输出限制为仅发送到一个类的消息,可以添加如下条件

(int)strcmp((char*)对象_getClassName($r0),“NSString”)==0


要在设备上的Xcode 6下跟踪应用程序代码,我必须使用以下调试器表达式

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($arg1),$arg2)

如果要在64位模拟器中记录方法,请使用以下命令:

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($rdi), (char *) $rsi)
或者,如果不起作用,请按以下方式记录:


其主要思想是对对象(self)使用$rdi,对选择器使用$rsi。

我将使用它来避免在运行发布版本时出现大量日志语句。或者,更好的方法是,制作一个使用不同的
#ifdef
的版本,这样您就可以独立于调试或发布版本打开和关闭方法日志记录。这假设方法内部没有返回,从而触发该方法的早期退出。在这种情况下,程序似乎正在进入方法而从未离开。DTrace脚本是我在回答中描述的吗?如果是这样的话,那只有在模拟器上运行时才会起作用。此外,它只跟踪在
-applicationdFinishLaunching:
中调用的方法,因此如果使用较新的
-application:didFinishLaunchingWithOptions:
,它将不会显示任何内容。您可以编辑脚本以反映此更新的方法,也可以简单地删除条件以使其记录所有内容。嗨,Brad。是的,这是你博客上的代码。我做了更改,但没有成功,但这只是因为我缺乏DTrace的经验。也许脚本的处理方式发生了一些变化。我来看看。好主意,但正如你说的,当你运行它的时候有点不知所措。在xcode 4中尝试这个,得到了这样一个“错误:'printf'不是一个有效的命令。”这一个有效expr--(void)printf([%s,%s]\n),(char)object_getClassName(*(long)($esp+4)),(char*)*(long*)($esp+8)),它开始记录一个永无止境的列表,当应用程序启动时?在断点设置的情况下,有没有办法避免ssytem调用?这在模拟器(Xcode 8)上对我很有效:
expr--(void)printf([%s%s]\n),(char*)object_getClassName(*(long*)($rdi)),(char*)($rsi))
它只是在抛出错误:使用未声明的标识符“$esp”错误:1分析表达式时出错“现在一遍又一遍,这是因为$esp是一个x86寄存器,它只存在于模拟器中-->此命令只在模拟器中工作。这在XCode 6.1中失败,并显示以下消息:
进程已返回到表达式求值前的状态。错误:执行被中断,原因:试图取消对无效指针的引用。
知道如何修改语句使其工作吗?在XCode 6.1中,此操作失败,并显示以下消息:
进程已返回到表达式求值之前的状态。错误:执行被中断,原因:试图取消引用无效指针。
知道如何修改语句使其工作吗?在ARM64上,这需要是
expr-(void)printf([%s%s]\n),(char*)object\u getClassName($x0),$x1)
@bcattle第一个参数需要是一个对象。这对我来说现在起作用了:
expr--(void)printf([%s%s]\n),(char*)object\u getClassName(@($x0)),$x1)
在模拟器中:(int)strc