NSLog den Methodennamen mit Objective-C im iPhone

153

Derzeit definieren wir uns einen erweiterten Protokollmechanismus, um den Klassennamen und die Quellzeilennummer des Protokolls auszudrucken.

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

Zum Beispiel, wenn ich NCLog aufrufe (@ "Hallo Welt"); Die Ausgabe wird sein:

<ApplicationDelegate:10>Hello world

Jetzt möchte ich auch den Methodennamen wie folgt abmelden:

<ApplicationDelegate:applicationDidFinishLaunching:10>Hello world

Dies würde unser Debuggen einfacher machen, wenn wir wissen, welche Methode aufgerufen wird. Ich weiß, dass wir auch einen Xcode-Debugger haben, aber manchmal möchte ich das Debuggen auch durch Abmelden durchführen.

Wodkhang
quelle
In meinem letzten iPhoneProjekt habe ich dies tatsächlich manuell gemacht. Würde gerne die Antwort darauf sehen.
Jacob Relkin
Mögliches Duplikat: stackoverflow.com/questions/969130/…
erkanyildiz

Antworten:

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

Swift 3 und höher

print(#function)
nach vorne gezogen
quelle
120
Sie sollten es wirklich verwenden NSLog(@"%@", NSStringFromSelector(_cmd)), wenn Sie es verwenden _cmdmöchten, da AFAIK Apple _cmdals Typ deklariert SEL, nicht als C-String. Nur weil es zufällig als C-String implementiert ist (ab den aktuellen Versionen von Mac OS X und iPhone OS), heißt das nicht, dass Sie es auf diese Weise verwenden sollten, da Apple es in einem Betriebssystem-Update ändern könnte.
Nick Forge
5
Ja, NSStringFromSelector ist die richtigere Antwort. Ich verwende _cmd nie als c-Zeichenfolge für etwas anderes als Debug-Code.
gezogen
Wow, der Compiler beschwert sich über Zeigerinkompatibilität, aber es funktioniert ... Also ist _cmd (Typ: SEL) wirklich ein Zeichen * !?
Nicolas Miari
3
Methodenaufrufe wie [self doSomething:arg1 somethingElse:arg2]werden in den C-Funktionsaufruf konvertiert objc_msgSend(self, "doSomething:somethingElse:, arg1, arg2);. Der zweite Parameter von objc_msgSend()nimmt a char*. Denken Sie daran, dass die Objective-C-Laufzeit dynamisch ist und tatsächlich eine Nachschlagetabelle verwendet, um herauszufinden, welche Methode für welche Klasse aufgerufen werden soll. Daher ist ein char * praktisch, da Methoden in der Nachschlagetabelle als Zeichenfolgen dargestellt werden.
Jack Lawrence
1
Für Swift 2.2 sollteprint("\(#function)")
Jake Lin
161

Um Ihre Frage technisch zu beantworten, möchten Sie:

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

Oder Sie könnten auch tun:

NSLog(@"%s", __PRETTY_FUNCTION__);
Dave DeLong
quelle
2
Mit __FUNCTION__und seinem hübschen Äquivalent ist es auch in C-Funktionen verfügbar.
Georg Fritzsche
NB __FUNCTION__enthält auch den Klassennamen
OrangeDog
1
Gibt es einen Unterschied bei der Verwendung von NSLog (@ "% s", _func_ ) ? ODER NSLog (@ "% s", _PRETTY_FUNCTION_ ) ???
Ravi
82

tl; dr

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

Einzelheiten

Apple hat eine Seite mit technischen Fragen und Antworten : QA1669 - Wie kann ich meinen Protokollierungsanweisungen Kontextinformationen wie die aktuelle Methode oder Zeilennummer hinzufügen?

So unterstützen Sie die Protokollierung:

  • Der C-Präprozessor bietet einige Makros .
  • Objective-C bietet Ausdrücke (Methoden).
    • Übergeben Sie das implizite Argument für den Selektor der aktuellen Methode:_cmd

Rufen Sie, wie in anderen Antworten angegeben, Folgendes auf, um lediglich den Namen der aktuellen Methode zu erhalten:

NSStringFromSelector(_cmd)

Um die aktuellen Methodennamen zu erhalten und aktuelle Zeilennummer, verwenden Sie diese beiden Makros __func__und __LINE__wie hier zu sehen:

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

Ein weiteres Beispiel… Codeausschnitte, die ich in der Code-Snippet-Bibliothek von Xcode aufbewahre:

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

… Und TRACE statt ERROR…

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

… Und eine längere mit einer weichcodierten Beschreibung, die einen Wert ( [rows count]) übergibt …

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

Präprozessor-Makros für die Protokollierung

Beachten Sie die Verwendung von zwei Unterstrichen auf beiden Seiten des Makros.

| Makro | Format | Beschreibung
  __func__% s Aktuelle Funktionssignatur
  __LINE__% d Aktuelle Zeilennummer
  __FILE__% s Vollständiger Pfad zur Quelldatei
  __PRETTY_FUNCTION__% s Wie __func__, enthält jedoch ausführlich
                                    Geben Sie Informationen in C ++ - Code ein. 

Ausdrücke für die Protokollierung

| Ausdruck | Format | Beschreibung
  NSStringFromSelector (_cmd)% @ Name des aktuellen Selektors
  NSStringFromClass ([Selbstklasse])% @ Klassenname des aktuellen Objekts
  [[NSString% @ Name der Quellcodedatei
    stringWithUTF8String: __ FILE__]   
    lastPathComponent] 
  [NSThread callStackSymbols]% @ NSArray der Stapelverfolgung

Protokollierungs-Frameworks

Einige Protokollierungsframeworks können auch beim Abrufen der aktuellen Methode oder Zeilennummer hilfreich sein. Ich bin mir nicht sicher, da ich ein großartiges Protokollierungsframework in Java ( SLF4J + LogBack ) verwendet habe, aber nicht Cocoa.

In dieser Frage finden Sie Links zu verschiedenen Cocoa-Protokollierungsframeworks.

Name des Selektors

Wenn Sie eine Selector-Variable (ein SEL ) haben, können Sie den Methodennamen ("message") auf zwei Arten drucken, wie in diesem Codec- Blogbeitrag beschrieben :

  • Verwenden des Objective-C-Aufrufs von NSStringFromSelector :
    NSLog(@"%@", NSStringFromSelector(selector) );
  • Verwenden Sie gerade C:
    NSLog(@"%s", selector );

Diese Informationen stammen aus der verlinkten Apple-Dokumentseite vom 19.07.2013. Diese Seite wurde zuletzt am 04.10.2011 aktualisiert.

Basil Bourque
quelle
1
Für C verwenden, sel_getName(SEL)da SEL ein undurchsichtiger Typ ist und möglicherweise nicht immer einchar *
Ethan Reesor
8
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C
print(__FUNCTION__) // Swift
Huynh Inc.
quelle
4
Für alle, die in Zukunft auf diese Antwort stoßen: Sie entspricht der akzeptierten Antwort, aber die akzeptierte Antwort war anders, als diese veröffentlicht wurde (die akzeptierte Antwort wurde 2014 bearbeitet). Ich wollte gerade abstimmen, aber nach einer kleinen Untersuchung stimmte
ich
0

Es ist eigentlich genauso einfach wie:

printf(_cmd);

Aus irgendeinem Grund erlaubt iOS, _cmd als Literalzeichen ohne Kompilierungswarnung zu übergeben. Wer weiß

Albert Renshaw
quelle
0

In Swift 4:

func test () {

print(#function)

}}

test () // drucke den Wert "test ()"

Ankit garg
quelle