11

Possible Duplicate:
Intercept method call in Objective-C
How to log all methods used in iOS app

For example, a UIViewController object in iOS receives many messages before its view is shown to a user:

  1. viewWillAppear
  2. viewWillLayoutSubviews
  3. viewDidLayoutSubviews
  4. viewDidAppear
  5. ...

because the framework's source code is not viewable, we have to rely on books or blogs, or is there a way to print out or monitor all the messages sent to this object by (1) Objective-C, or (2) by any tool?

Community
  • 1
  • 1
nonopolarity
  • 146,324
  • 131
  • 460
  • 740
  • @trojanfoe: Good find. It should be noted that the accepted answer there _won't_ do what (I believe) 動靜能量 is asking for because it requires the method to be known in advance, but either [Ole Begemann's](http://stackoverflow.com/a/1632030/) or [emp's](http://stackoverflow.com/a/7130268/603977) answer will work. – jscs May 25 '12 at 06:38
  • In fact, I was essentially going to suggest emp's solution myself. – jscs May 25 '12 at 06:39
  • 1
    it's not a duplicate, he's asking to intercept all methods, not just one... using swizzling here means re-implement the whole class. – bontoJR May 25 '12 at 06:41
  • See this blog post: http://www.dribin.org/dave/blog/archives/2006/04/22/tracing_objc/ –  May 25 '12 at 07:01
  • See also https://stackoverflow.com/questions/3790772/how-do-i-see-every-method-called-when-i-run-my-application-in-the-iphone-simulat – matt Apr 02 '22 at 00:56

2 Answers2

17

Rather than my comment, the best approach that I used (and still use) is calling:

(void)instrumentObjcMessageSends(YES);

When I need to start logging all messages and then:

(void)instrumentObjcMessageSends(NO);

Don't forget to add #import <objc/runtime.h>.
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.

What is printed is something like this:

- 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

Note: It has been a while since I used this approach for the last time and it looks like this approach doesn't log private methods subclassed. So, if you have a DummyClass with -(void)_dummyMethod as private and then a DummySubClass with a -(void)_dummyMethod implementation, the message will not be logged.

For iOS, this works only on Simulator.

bontoJR
  • 6,995
  • 1
  • 26
  • 40
  • 3
    +1, though this is Mac-only. On iOS, this is not implemented. –  May 25 '12 at 07:58
  • @H2CO3 : works only on Simulator, thanks for pointing it out, I'll add the note. – bontoJR May 25 '12 at 08:00
  • 1
    Yes, and it's intentional. If it was there, jailbreaker devs could reverse engineer the whole OS and it would be as straightforward as injecting a dylib into an arbitrary process (which is a piece of cake using MobileSubstrate). –  May 25 '12 at 08:49
  • 1
    You can also do something similar using symbolic breakpoints, as I describe in [this answer](http://stackoverflow.com/a/7275049/19679), and I believe that will also work on the device if you adjust the memory addresses appropriately. – Brad Larson May 25 '12 at 20:02
14

You can use DTrace to monitor a running application to see the methods and the classes that are called. You can easily monitor an iOS app running in the Simulator using DTrace on the command line, First you will need to find the PID of the application using ps and then you can run a DTrace probe like the following:

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

where 1234 is the process ID of the app.

This will produce output that looks like the following:

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

If you are only interested in tracing a single class, UIView for example, you could use:

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

If you wanted to trace all calls to dealloc on all classes, you would use:

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

Obviously, you could combine these to only see UIView deallocs:

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

If you want to be able to distinguish a specific object of a class you could also print the memory address of the object (self) using the following:

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

DTrace is extremely powerful and can do considerably more than I've shown here.

mttrb
  • 8,297
  • 3
  • 35
  • 57
  • 1
    I agree that DTrace is powerful. Some suggestions: use a wildcard after the class to catch methods defined in categories. Include the `tid` in the printout. Also include the `timestamp`. The problem is that DTrace can receive data out of order and you may have to reconstruct the order. You may also have to tease apart the streams from different threads. See [this archived email](http://lists.apple.com/archives/xcode-users/2008/Oct/msg00114.html) with an attached script that does this plus tracks call depth within the thread. It uses an `order` variable rather than `timestamp`. – Ken Thomases May 25 '12 at 07:13
  • @KenThomases Excellent points and I like the attached script – mttrb May 25 '12 at 07:18
  • 1
    You can also create a custom instrument for this, an example of which I describe at the end of [this article over at MacResearch](http://www.macresearch.org/tuning-cocoa-applications-using-dtrace-custom-static-probes-and-instruments). – Brad Larson May 25 '12 at 19:57