可以将发送到Objective-C中的对象的消息进行监视或打印出来吗?

可能存在重复:
  在Objective-C中拦截方法调用
  如何记录iOS应用程序中使用的所有方法

例如,iOS中的 UIViewController 对象在其视图向用户显示之前会收到许多消息:

  1. <�代码> viewWillAppear中</代码>
  2. <�代码> viewWillLayoutSubviews </代码>
  3. <�代码> viewDidLayoutSubviews </代码>
  4. <�代码> viewDidAppear </代码>
  5. ...

因为框架的源代码是不可见的,所以我们必须依靠书籍或博客,或者有办法通过(1)Objective-C或(2)通过任何工具打印或监控发送到该对象的所有消息?

10
额外 编辑
意见: 1
@trojanfoe:很好找。应该指出,那里接受的答案不会做什么(我相信)动静能量所要求的,因为它需要事先知道方法,但是要么 Ole Begemann的emp 的答案将可用。
额外 作者 Josh Caswell,
实际上,我本质上是要自己提出emp的解决方案。
额外 作者 Josh Caswell,
它不是重复的,他要求拦截所有方法,而不仅仅是一个......在这里使用混合就意味着重新实现整个班级。
额外 作者 bontoJR,

2 答案

我使用(而且仍在使用)的最佳方法不是我的评论,而是呼吁:

(void)instrumentObjcMessageSends(YES);

当我需要开始记录所有消息时,然后:

(void)instrumentObjcMessageSends(NO);

Don't forget to add #import .
When I don't need it anymore. The annoying thing is that the log is created under /tmp/msgSends- and this means that you have to open the terminal and use tail to see it in a readable way.

印刷的东西是这样的:

- CustomTableViewController UIViewController _parentModalViewController
- CustomTableViewController UIViewController isPerformingModalTransition
- CustomTableViewController UIViewController setInAnimatedVCTransition:
- CustomTableViewController UIViewController viewWillMoveToWindow:
- CustomTableViewController UIViewController isPerformingModalTransition
- CustomTableViewController UIViewController parentViewController
- CustomTableViewController UIViewController _popoverController
- CustomTableViewController UIViewController _didSelfOrAncestorBeginAppearanceTransition
- CustomTableViewController UIViewController parentViewController
- CustomTableViewController UIViewController __viewWillDisappear:
- CustomTableViewController UIViewController _setViewAppearState:isAnimating:
- CustomTableViewController UIViewController automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers

注意:自从我最后一次使用这种方法以来,这已经有一段时间了,它看起来像这种方法不记录私有方法的子类。因此,如果您的 DummyClass- (void)_dummyMethod 设置为private,然后使用 - _dummyMethod创建 DummySubClass 实现,消息不会被记录。

对于iOS,这仅适用于模拟器。

14
额外
+1非常酷的发现。
额外 作者 Rog,
您也可以使用符号断点来做类似的事情,正如我在这个答案中所描述的那样,我相信这也可以在设备,如果你适当调整内存地址。
额外 作者 Brad Larson,
@ H2CO3:只能在模拟器上使用,谢谢指出,我会添加注释。
额外 作者 bontoJR,

您可以使用DTrace监视正在运行的应用程序以查看调用的方法和类。您可以在命令行上使用DTrace轻松监控在Simulator中运行的iOS应用程序。首先,您需要使用 ps 查找应用程序的PID,然后运行DTrace探针,如下所示:

sudo dtrace -q -n 'objc1234:::entry { printf("%s %s\n", probemod, probefunc); }' 

其中1234是应用程序的进程ID。

这将产生如下所示的输出:

UIStatusBarItemView -isVisible
UIStatusBarLayoutManager -_positionAfterPlacingItemView:startPosition:
UIView(Geometry) -frame
CALayer -frame
UIStatusBarLayoutManager -_startPosition
UIView(Geometry) -bounds
CALayer -bounds
UIStatusBarItemView -standardPadding
UIStatusBarItem -appearsOnLeft
UIStatusBarItem -leftOrder

如果你只想追踪一个类,例如 UIView ,你可以使用:

sudo dtrace -q -n 'objc1234:UIView::entry { printf("%s %s\n", probemod, probefunc); }'

如果您想跟踪所有类上的所有对 dealloc 的调用,您可以使用:

sudo dtrace -q -n 'objc1234::-dealloc:entry { printf("%s %s\n", probemod, probefunc); }'

显然,你可以将它们结合起来,只看到 UIView dealloc s:

sudo dtrace -q -n 'objc1234:UIView:-dealloc:entry { printf("%s %s\n", probemod, probefunc); }'

如果您希望能够区分某个类的特定对象,则还可以使用以下命令打印该对象的内存地址( self ):

sudo dtrace -q -n 'objc1234:UIView:-dealloc:entry { printf("%s (0x%p) %s\n", probemod, arg0, probefunc); }'

DTrace功能非常强大,可以做得比我在这里展示的要多得多。

14
额外
您也可以为此创建一个自定义工具,这是我在这篇文章在MacResearch上
额外 作者 Brad Larson,
我同意DTrace功能强大。一些建议:在类后面使用通配符来捕获类别中定义的方法。在打印输出中包含 tid 。还包括 timestamp 。问题是DTrace可能会按顺序接收数据,您可能需要重新构建订单。你也可能不得不把不同线程的流分开。请参阅此已归档的电子邮件,并附上脚本这个加号跟踪线程内的调用深度。它使用 order 变量而不是 timestamp
额外 作者 Ken Thomases,
@KenThomases优秀的点,我喜欢附加的脚本
额外 作者 mttrb,