2012-05-25 11 views
10

Eventuali duplicati:
Intercept method call in Objective-C
How to log all methods used in iOS appI messaggi inviati ad un oggetto in Objective-C possono essere controllati o stampati?

Ad esempio, un oggetto UIViewController in IOS riceve molti messaggi prima della sua vista è mostrato a un utente:

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

perché il codice sorgente del framework non è visualizzabile, dobbiamo fare affidamento sui libri o blog, o c'è un modo per stampare fuori o monitorare tutti i messaggi inviati a questo oggetto da (1) Objective-C o (2) da qualsiasi strumento?

+0

@trojanfoe: buona ricerca. Va notato che la risposta accettata non fa ciò che (credo) 動靜 能量 sta chiedendo perché richiede che il metodo sia conosciuto in anticipo, ma sia [Ole Begemann's] (http://stackoverflow.com/a/1632030 /) o [emp's] (http://stackoverflow.com/a/7130268/603977) la risposta funzionerà. –

+0

In effetti, stavo essenzialmente suggerendo la soluzione di emp da solo. –

+0

non è un duplicato, sta chiedendo di intercettare tutti i metodi, non solo uno ... usando lo swizzling qui significa re-implementare l'intera classe. – bontoJR

risposta

14

piuttosto che il mio commento, l'approccio migliore che ho usato (ed uso ancora) sta chiamando:

(void)instrumentObjcMessageSends(YES); 

Quando ho bisogno di avviare la registrazione di tutti i messaggi e poi:

(void)instrumentObjcMessageSends(NO); 

don' t dimenticare di aggiungere #import <objc/runtime.h>.
Quando non ne ho più bisogno. La cosa fastidiosa è che il registro viene creato sotto /tmp/msgSends- e questo significa che devi aprire il terminale e usare tail per vederlo in modo leggibile.

ciò che è stampato è qualcosa di simile:

- 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 

Nota: E 'stato un po' da quando ho usato questo approccio per l'ultima volta e sembra che questo approccio non registra i metodi privati ​​sottoclasse. Pertanto, se si dispone di con -(void)_dummyMethod come privato e quindi di DummySubClass con un'implementazione -(void)_dummyMethod, il messaggio non verrà registrato.

Per iOS, questo funziona solo su Simulator.

+0

+1 scoperta molto interessante. – Rog

+3

+1, anche se questo è solo per Mac. Su iOS, questo non è implementato. –

+0

@ H2CO3: funziona solo su Simulator, grazie per la segnalazione, aggiungerò la nota. – bontoJR

14

È possibile utilizzare DTrace per monitorare un'applicazione in esecuzione per visualizzare i metodi e le classi chiamate. Si può facilmente monitorare un app iOS in esecuzione nel simulatore usando DTrace sulla riga di comando, In primo luogo è necessario trovare il PID dell'applicazione utilizzando ps e quindi è possibile eseguire una sonda DTrace come la seguente:

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

dove 1234 è l'ID di processo dell'app.

Questo produrrà un output che appare simile al seguente:

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

Se siete interessati solo a tracciare una singola classe, UIView ad esempio, è possibile utilizzare:

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

Se si voleva per tracciare tutte le chiamate a dealloc su tutte le classi, si può usare:

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

Ovviamente, è possibile combinare questi per vedere solo UIViewdealloc s:

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

Se si vuole essere in grado di distinguere un oggetto specifico di una classe si potrebbe anche stampare l'indirizzo di memoria dell'oggetto (self) utilizzando il seguente:

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

DTrace è estremamente potente e può fare molto più di quanto non abbia mostrato qui.

+1

Concordo sul fatto che DTrace sia potente. Alcuni suggerimenti: utilizzare un carattere jolly dopo la classe per individuare i metodi definiti nelle categorie. Includere il 'tid' nella stampa. Includere anche il 'timestamp'. Il problema è che DTrace può ricevere dati fuori servizio e potrebbe essere necessario ricostruire l'ordine. Potrebbe anche essere necessario separare i flussi da diversi thread. Vedi [questa email archiviata] (http://lists.apple.com/archives/xcode-users/2008/Oct/msg00114.html) con uno script allegato che esegue questa operazione, oltre a tracciare la profondità della chiamata all'interno del thread. Usa una variabile 'order' piuttosto che' timestamp'. –

+0

@KenThomases Punti eccellenti e mi piace la sceneggiatura allegata – mttrb

+1

Puoi anche creare uno strumento personalizzato per questo, un esempio che descrivo alla fine di [questo articolo su MacResearch] (http://www.macresearch.org/ tuning-cacao-applicazioni-utilizzando-dtrace-custom-statico-sonde-e-strumenti). –

Problemi correlati