NSLog il nome del metodo con Objective-C in iPhone


153

Attualmente, ci stiamo definendo un meccanismo di registro esteso per stampare il nome della classe e il numero di riga di origine del registro.

#define NCLog(s, ...) NSLog(@"<%@:%d> %@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], \
    __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__])

Ad esempio, quando chiamo NCLog (@ "Hello world"); L'output sarà:

<ApplicationDelegate:10>Hello world

Ora voglio anche disconnettere il nome del metodo come:

<ApplicationDelegate:applicationDidFinishLaunching:10>Hello world

Quindi, questo renderebbe il nostro debug più semplice quando potremo sapere quale metodo viene chiamato. So che abbiamo anche il debugger Xcode ma a volte, voglio anche fare il debug disconnettendomi.


Nel mio ultimo iPhoneprogetto, l'ho fatto manualmente. Mi piacerebbe vedere la risposta a questo.
Jacob Relkin,

Risposte:


261
print(__FUNCTION__) // Swift
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C

Swift 3 e versioni successive

print(#function)

120
Dovresti davvero usare NSLog(@"%@", NSStringFromSelector(_cmd)), se hai intenzione di usare _cmd, poiché AFAIK Apple dichiara _cmdcome tipo SEL, non una stringa C. Solo perché sembra essere implementato come una stringa C (a partire dalle versioni attuali di Mac OS X e del sistema operativo iPhone) non significa che dovresti usarlo in questo modo, poiché Apple potrebbe cambiarlo in un aggiornamento del sistema operativo.
Nick Forge,

5
Sì, NSStringFromSelector è la risposta più corretta. Non uso mai _cmd come stringa c per tutto tranne che per il codice di debug.
disegnato

Wow, il compilatore si lamenta dell'incompatibilità del puntatore, ma funziona ... Quindi _cmd (tipo: SEL) è davvero un carattere *!?
Nicolas Miari,

3
Metodo chiama come [self doSomething:arg1 somethingElse:arg2]vengono convertiti nella chiamata di funzione C objc_msgSend(self, "doSomething:somethingElse:, arg1, arg2);. Il secondo parametro di objc_msgSend()accetta a char*. Ricorda che, poiché il runtime Objective-C è dinamico, utilizza effettivamente una tabella di ricerca per capire quale metodo su quale classe chiamare, quindi un char * è conveniente poiché i metodi sono rappresentati come stringhe nella tabella di ricerca.
Jack Lawrence,

1
Per Swift 2.2 dovrebbe usareprint("\(#function)")
Jake Lin

161

Per rispondere tecnicamente alla tua domanda, vuoi:

NSLog(@"<%@:%@:%d>", NSStringFromClass([self class]), NSStringFromSelector(_cmd), __LINE__);

Oppure potresti anche fare:

NSLog(@"%s", __PRETTY_FUNCTION__);

2
Con __FUNCTION__ed è abbastanza equivalente anche essere disponibile in funzioni C.
Georg Fritzsche,

NB __FUNCTION__include anche il nome della classe
OrangeDog

1
c'è qualche differenza usando NSLog (@ "% s", _func_ ); O NSLog (@ "% s", _PRETTY_FUNCTION_ ) ???
Ravi,

83

tl; dr

NSLog( @"ERROR %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

Dettagli

Apple ha una pagina di domande e risposte tecniche : QA1669 - Come posso aggiungere informazioni di contesto - come il metodo corrente o il numero di riga - alle mie dichiarazioni di registrazione?

Per aiutare con la registrazione:

  • Il preprocessore C fornisce alcune macro .
  • Objective-C fornisce espressioni (metodi).
    • Passa l' argomento implicito per il selettore del metodo corrente:_cmd

Come indicato da altre risposte, per ottenere semplicemente il nome del metodo corrente, chiamare:

NSStringFromSelector(_cmd)

Per ottenere il nome del metodo corrente e il numero di riga corrente, utilizzare queste due macro __func__e __LINE__come mostrato qui:

NSLog(@"%s:%d someObject=%@", __func__, __LINE__, someObject);

Un altro esempio ... Snippet di codice che conservo nella libreria di snippet di codice di Xcode:

NSLog( @"ERROR %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

... e TRACE invece di ERRORE ...

NSLog( @"TRACE %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

... e una più lunga usando una descrizione codificata che passa un valore ( [rows count]) ...

NSLog( @"TRACE %@ METHOD %s:%d.", [NSString stringWithFormat:@"'Table of Contents.txt' file's count of Linefeed-delimited rows: %u.", [rows count]] , __func__, __LINE__ );

Macro del preprocessore per la registrazione

Si noti l'uso di una coppia di caratteri di sottolineatura attorno a entrambi i lati della macro.

| Macro | Formato | Descrizione
  __func__% s Firma della funzione corrente
  __LINE__% d Numero riga corrente
  __FILE__% s Percorso completo del file di origine
  __PRETTY_FUNCTION__% s Come __func__, ma include dettagli
                                    digitare le informazioni nel codice C ++. 

Espressioni per la registrazione

| Espressione | Formato | Descrizione
  NSStringFromSelector (_cmd)% @ Nome del selettore corrente
  NSStringFromClass ([self class])% @ Nome classe dell'oggetto corrente
  [[NSString% @ Nome file codice sorgente
    stringWithUTF8String: __ FILE__]   
    lastPathComponent] 
  [NSThread callStackSymbols]% @ NSArray di traccia stack

Frame di registrazione

Alcuni framework di registrazione possono aiutare anche a ottenere il metodo corrente o il numero di riga. Non ne sono sicuro, poiché ho usato un ottimo framework di registrazione in Java ( SLF4J + LogBack ) ma non Cocoa.

Vedi questa domanda per i collegamenti a vari framework di registrazione Cocoa.

Nome del selettore

Se si dispone di una variabile Selector (un SEL ), è possibile stampare il nome del metodo ("messaggio") in uno dei due modi descritti da questo post del blog Codec :

  • Utilizzando la chiamata Objective-C a NSStringFromSelector :
    NSLog(@"%@", NSStringFromSelector(selector) );
  • Usando la C diritta:
    NSLog(@"%s", selector );

Queste informazioni sono tratte dalla pagina dei documenti Apple collegata dal 19/07/2013. Quella pagina è stata aggiornata l'ultima volta il 2011-10-04.


1
Per C, usa sel_getName(SEL)poiché SEL è un tipo opaco e potrebbe non essere sempre unchar *
Ethan Reesor il

8
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C
print(__FUNCTION__) // Swift

4
Per chiunque trovi questa risposta in futuro: equivale alla risposta accettata, ma la risposta accettata era diversa, quando questa è stata pubblicata (la risposta accettata è stata modificata nel 2014). Stavo per votare in
negativo

0

In realtà è semplice come:

printf(_cmd);

Per qualche motivo iOS consente a _cmd di essere passato come carattere letterale senza nemmeno un avviso di compilazione. Chissà


0

In Swift 4:

func test () {

print(#function)

}

test () // stampa il valore "test ()"

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.