Можно ли отслеживать или распечатывать сообщения, отправленные объекту в Objective-C?

Возможный дубликат:
Вызов метода перехвата в Objective-C
Как регистрировать все методы, используемые в приложении iOS

Например, объект UIViewController в iOS получает много сообщений, прежде чем его представление будет показано пользователю:

  • viewWillAppear
  • viewWillLayoutSubviews
  • viewDidLayoutSubviews
  • viewDidAppear
  • ...

потому что исходный код рамки не доступен для просмотра, мы должны полагаться на книги или блоги, или есть способ распечатать или контролировать все сообщения, отправленные этому объекту, с помощью (1) Objective-C или (2) любым инструментом?

Ответ 1

Вместо моего комментария лучший подход, который я использовал (и до сих пор использую), вызывает:

(void)instrumentObjcMessageSends(YES);

Когда мне нужно начать регистрировать все сообщения, а затем:

(void)instrumentObjcMessageSends(NO);

Не забудьте добавить #import <objc/runtime.h>.
Когда мне это больше не нужно. Досадно, что журнал создан под /tmp/msgSends-, и это означает, что вам нужно открыть терминал и использовать tail, чтобы увидеть его читаемым способом.

Что печатается, это примерно так:

- 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 как закрытый, а затем DummySubClass с реализацией -(void)_dummyMethod, сообщение не будет регистрироваться.

Для iOS это работает только на Simulator.

Ответ 2

Вы можете использовать DTrace для мониторинга запущенного приложения, чтобы увидеть методы и вызываемые классы. Вы можете легко контролировать приложение iOS, работающее в Simulator, используя DTrace в командной строке. Сначала вам нужно найти PID приложения с помощью ps, а затем вы можете запустить DTrace-зонд следующим образом:

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

где 1234 - это идентификатор процесса приложения.

Это приведет к выходу, который выглядит следующим образом:

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 чрезвычайно эффективен и может делать значительно больше, чем показано здесь.