Muss ich NSLog vor der Freigabe der Anwendung deaktivieren?


117

Wenn ich eine App für das iPhone freigebe, NSLog();wird sie beim Deaktivieren eine bessere Leistung erzielen?


1
In meinem aktuellen Projekt verwende ich UALogger . Die Produktion wird nicht angemeldet , wenn Sie nicht explizit danach fragen. Und hat andere Vorteile gegenüber normalem NSLog, wie z. B. Schweregrade (mit DEBUG , INFO usw.). Gut gemacht!
Anton Gaenko

1
Um Ihre Frage zu "Wird es besser funktionieren?" Zu beantworten. Ja, aber der Ertrag, den Sie erhalten, hängt davon ab, wie viele NSLog()Sie in Ihrer App haben. NSLog()Die Ausführung nimmt Zeit in Anspruch und erhöht den Laufzeitaufwand Ihrer App um zusätzlichen Aufwand. Wenn es die Leistung mit einem einfachen DEBUG-Präprozessor-Makro verbessert, sollten wir es deaktivieren.
Scott

Ich würde auch vorschlagen, wenn Sie viele NSLog / print-Anweisungen in Ihrem Code haben, es könnte vorschlagen, dass Sie einige Zeit damit verbringen sollten, mehr über den Debugger zu lernen. Ich setze regelmäßig Haltepunkte, die Informationen drucken, an denen ich interessiert bin, und fahre automatisch fort. Ja, es kann das Laufen etwas verlangsamen, aber in den meisten Fällen ist es nicht überwältigend. Außerdem bedingte Pausen, damit Sie untersuchen können, wenn etwas Unerwartetes passiert ist.
Bshirley

Antworten:


127

Eine Möglichkeit, dies zu tun, besteht darin, in Ihre Build-Einstellungen zu gehen und unter der Debug-Konfiguration einen Wert zum Wert "Präprozessor-Makros" hinzuzufügen, wie:

DEBUG_MODE=1

Stellen Sie sicher, dass Sie dies nur für die Debug-Konfiguration und nicht für Beta- oder Release-Versionen tun. Dann können Sie in einer gemeinsamen Header-Datei Folgendes tun:

#ifdef DEBUG_MODE
#define DLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define DLog( s, ... ) 
#endif

Anstatt nun den NSLog Einsatz DLogüberall. Beim Testen und Debuggen erhalten Sie Debug-Meldungen. Wenn Sie bereit sind, eine Beta- oder Endversion zu veröffentlichen, werden alle diese DLogZeilen automatisch leer und es wird nichts ausgegeben. Auf diese Weise ist keine manuelle Einstellung von Variablen oder Kommentierung NSLogserforderlich. Die Auswahl Ihres Build-Ziels kümmert sich darum.


In Xcode 4.5 wird eine Warnung ausgegeben, die besagt: "Die implizite Deklaration der Funktion 'DLog' ist in C99 ungültig", sodass diese Funktion nicht funktioniert.
Sergey Grischyov

2
@SergiusGee: Sie erhalten die implizite Deklarationswarnung, wenn die Deklaration für die Funktion nicht gefunden werden kann. In diesem Fall glauben Sie, dass Sie versuchen, sie zu deklarieren. Stellen Sie sicher, dass Ihre Klasse Zugriff auf die Header-Datei hat, in der dies deklariert ist.
Sudo rm -rf

1
Ich muss mich nicht abmelden, da es Ihnen die Möglichkeit nimmt, bessere Fehlerberichte von Benutzern zu erhalten. Verwenden Sie asynchrone Protokollierung und logLevels, um den Leistungstreffer auf nahezu Null zu begrenzen! (Siehe Kakao Holzfäller oder Java
Log4J

2
Ich würde eher mit #if als mit #ifdef gehen, da DEBUG_MODE 0 immer noch den wahren Weg gehen wird
Grady Player

1
Dies beantwortet nicht die Frage
Martin Mlostek

117

Update für Xcode 5 & iOS 7

Anmerkung: für eine Xcode 7 / Swift 2.1 Lösung zu entfernen print () Anweisungen in einer Release - Build, findet meine Antwort hier .

Ja, Sie sollten alle NSLog-Anweisungen in Ihrem Release-Code entfernen, da dies nur Ihren Code verlangsamt und in einer Release-Version nicht von Nutzen ist. Glücklicherweise ist es in Xcode 5 (iOS 7) erstaunlich einfach, alle Ihre NSLog-Anweisungen in Release-Builds "automatisch" zu entfernen. Warum also nicht?

Zuerst die 3 Schritte, dann eine Erklärung

1) Suchen Sie in Ihrem Xcode-Projekt die Datei 'yourProjectName-prefix.pch' (normalerweise finden Sie diese unter der Gruppe 'unterstützende Dateien', in der sich Ihre main.m-Datei befindet

2) Fügen Sie diese 3 Zeilen am Ende der '.pch'-Datei hinzu:

#ifndef DEBUG
   #define NSLog(...);
#endif

3) Testen Sie den Unterschied zwischen Ihrer 'Debug'- und' Release'-Version. Eine Möglichkeit, dies zu tun, besteht darin, "Schema bearbeiten" -> "App-Namen ausführen" -> unter der Registerkarte "Info" über das Dropdown-Feld zwischen Debug & Release auszuwählen. In der Release-Version wird keine NSLog-Ausgabe in der Debug-Konsole angezeigt!

Wie funktioniert das alles?

Zunächst muss man wissen, dass ein Präprozessor relativ "dumm" ist und nur als "Textersatz" fungiert, bevor der Compiler aufgerufen wird. Es ersetzt alles, was Sie "definieren", durch das, was der #defineAnweisung folgt .

#define NSLog(...);

Das (...)steht für 'irgendetwas' zwischen den Klammern (). Beachten Sie auch das ;am Ende. Dies ist nicht unbedingt erforderlich, da der Compiler dies wegoptimieren wird, aber ich möchte es dort platzieren, da es "korrekter" ist. Nach unserem #definegibt es 'nichts', also ersetzt der Präprozessor es durch 'nichts' und wirft einfach die gesamte Zeile weg, beginnend NSLog...bis einschließlich ;.

define-Anweisungen können mit #ifdef(falls definiert) oder #ifndef(falls nicht definiert) bedingt gemacht werden.

hier schreiben wir #ifndef DEBUG, was bedeutet "wenn das Symbol DEBUG nicht definiert ist". Die #ifdefoder #ifndefmüssen mit geschlossen werden#endif

Xcode 5 definiert standardmäßig das 'DEBUG'-Symbol für uns, wenn der Build-Modus' DEBUG 'ist. In 'release' ist dies nicht definiert. Sie können dies unter Ihren Projekteinstellungen auf der Registerkarte "Build-Einstellungen" überprüfen -> scrollen Sie nach unten zum Abschnitt "Apple LLVM 5.0 - Vorverarbeitung" -> Präprozessor-Makros. Sie werden sehen, dass das Symbol 'DEBUG' für Release-Builds nicht definiert ist!

Schließlich wird die .pch-Datei von Xcode automatisch erstellt und während der Kompilierungszeit automatisch in jede Quelldatei aufgenommen. Es ist also so, als hätten Sie das #defineGanze in jede Ihrer Quelldateien eingefügt.


1
Danke @Whasssaaahhh, es funktioniert großartig. Vermeiden Sie es, Code in Protokollanweisungen einzufügen! Der Präprozessor entfernt die gesamten NSLogAnweisungen, ohne Rücksicht darauf, was sich darin befindet.
Eric Platon

1
Wenn es sich um ein älteres Projekt handelt, das in Präprozessor-Makros kein Debug-Flag hat, ist es wichtig, das "Debug = 1" für das Projekt und nicht das Ziel hinzuzufügen
Priebe

1
Verwenden Sie auch nicht NSLogals Do-Nothing-Anweisung, z. B. setzen Sie if(AllCool) NSLog(@"Cool!Do Nothing!"); else...die NSLogin ein paar geschweiften Klammernif(AllCool) {NSLog(@"Cool!Do Nothing!");} else...
Arcady Bob

33

Fast alle obigen Antworten schlagen eine Lösung vor, erklären aber das Problem nicht. Ich habe in Google gesucht und den Grund gefunden. Hier ist meine Antwort:

Ja, wenn Sie NSLog in Ihrer Release-Version auskommentieren, wird die Leistung besser. Weil NSLog ziemlich langsam ist. Warum? NSLog führt zwei Aktionen aus: 1) Schreiben von Protokollnachrichten in Apple System Logging (ASL), 2) Wenn die App in xcode ausgeführt wird, schreibt sie auch in stderr.

Das Hauptproblem liegt im ersten. Um eine Thread-Sicherheit zu erreichen, wird bei jedem Aufruf von NSLog eine Verbindung zur ASL-Einrichtung hergestellt , eine Nachricht gesendet und die Verbindung geschlossen. Der Verbindungsvorgang ist sehr teuer. Ein weiterer Grund ist, dass NSLog einige Zeit damit verbringt, den Zeitstempel für die Protokollierung zu erhalten.

Referenz von hier .


23

Mein persönlicher Favorit ist die Verwendung eines variadischen Makros.

#ifdef NDEBUG
    #define NSLog(...) /* suppress NSLog when in release mode */
#endif

1
Wo legst du das hin?
user6631314

20

Zusätzlich zu all den Leuten, die klugerweise kommentiert haben, dass das Nicht-Anrufen NSLog()in der Produktion etwas schneller läuft, füge ich Folgendes hinzu:

Alle diese NSLog()Ausgabezeichenfolgen sind für jeden sichtbar, der Ihre App aus dem Store herunterlädt und mit dem Gerät ausführt, das an einen Mac angeschlossen ist, auf dem Xcode ausgeführt wird (über das Organizer-Fenster).

Abhängig davon, welche Informationen Sie protokollieren (und insbesondere, wenn Ihre App einen Server kontaktiert, eine Authentifizierung durchführt usw.), kann dies ein ernstes Sicherheitsproblem sein .


danke für die info - ist das irgendwo im doc oder hast du das gerade selbst entdeckt? Gilt das noch für den Druck in Swift?
Ronny Webers

Ich kann mich nicht erinnern, eine Dokumentation gelesen zu haben. Ich habe gerade meinen archivierten Build (dieselbe Binärdatei, die ich an den Store gesendet habe) auf meinem Gerät installiert und an Xcode angeschlossen. Ich habe keine Ahnung, ob es bei Swift genauso ist print(), aber höchstwahrscheinlich ist es das auch.
Nicolas Miari

@NicolasMiari Was meinst du mit in Xcode eingesteckt? Wie wir unsere Binärdatei in Xcode einbinden können, möchte ich eigentlich gleich ausprobieren. Also bitte vorschlagen. Vielen Dank.
iDevAmit

@iDeveloper Ich meine, laden Sie Ihre App aus dem AppStore auf ein Gerät (z. B. ein iPhone) herunter, schließen Sie dieses Gerät über USB an Xcode an, starten Sie Ihre App und sehen Sie sich die Protokolle im Xcode-Fenster "Geräte" an.
Nicolas Miari

3
@ Whasssaaahhh Druck wird nicht in der Gerätekonsole ausgegeben. Ich habe das gerade getestet
Anish Parajuli 11

13

Standardeinstellung des Projekts

In der aktuellen Standardeinstellung des Projekts in Xcode wird das NS_BLOCK_ASSERTIONSMakro in der Release-Version und DEBUG=1in der Debug-Version auf 1 gesetzt .

Daher bevorzuge ich die folgende Methode.

// NS_BLOCK_ASSERTIONS is defined by default, as shown in the screenshot above.
// Or, you can define yourself Flags in the `Other C Flags` -> `Release`.
#ifndef NS_BLOCK_ASSERTIONS
    #define _DEBUG
#endif

#ifdef _DEBUG
// for debug mode 
#define DLog(fmt,...) NSLog(@"%s " fmt, __FUNCTION, ##__VA_ARGS__) 
... /// something extra
#else
// for release mode
#define DLog(fmt,...) /* throw it away */
... /// something extra
#endif

5

Ja, Sie sollten es deaktivieren. Vor allem, wenn Sie versuchen, die Geschwindigkeit Ihres Codes zu maximieren. NSLogging von links und rechts verschmutzt das Systemprotokoll, das andere Entwickler möglicherweise zu durchsuchen versuchen, und es kann einen großen Einfluss auf den geschwindigkeitskritischen Code haben (innerhalb von Schleifen usw.). Ich habe versehentlich einige Protokollnachrichten einmal und einmal in einer rekursiven Funktion hinterlassen muss ein Update mit einer "30% Geschwindigkeitssteigerung!" ein paar Wochen später... ;-)


5

Alle guten Antworten, aber hier ist ein weiterer kleiner Trick, den Sie in Betracht ziehen können, hauptsächlich in der Entwicklungs- / Testphase Ihrer App.

Dies kann auch für den App-Release-Code nützlich sein, wenn Sie nur IHREN Debug-Code deaktivieren möchten und keine Nachrichten, die auf Probleme hinweisen, die außerhalb der direkten Kontrolle Ihres Codes liegen.

Der Trick:

Sie können NSLog pro .m-Datei deaktivieren, indem Sie einfach die folgende Zeile oben in die .m-Datei einfügen :

#define NSLog(...)

( HINWEIS: Legen Sie NICHT die .h-Datei, sondern nur die .m-Datei ab! )

Dadurch wird der Compiler nur ausgewertet, NSLog()indem stattdessen Ihr Präprozessor-Makro erweitert wird. Das Makro entfernt lediglich die Argumente.

Wenn Sie es wieder einschalten möchten, können Sie es jederzeit verwenden

#undef NSLog

Sie können beispielsweise einfach verhindern, dass NSLog für eine bestimmte Gruppe von Methoden aufgerufen wird, indem Sie Folgendes tun

#define NSLog(...)
-(void) myProblematicMethodThatSometimesNeedsDebugging {
    ...
}
#undef NSLog

3

NSLog ist langsam und sollte nicht für Release-Builds verwendet werden. Ein einfaches Makro wie das folgende deaktiviert es zusammen mit eventuellen Zusicherungen, die ebenfalls deaktiviert werden sollten. In dem selteneren Fall, in dem Sie NSLog in einem Release-Build möchten, rufen Sie es einfach direkt auf. Vergessen Sie nicht, "-DNDEBUG" zu Ihren Build-Einstellungen für "andere C-Flags" hinzuzufügen.

#ifdef NDEBUG
#define MYLog(f, ...) 
#else
#define MYLog(f, ...) NSLog(f, ## __VA_ARGS__)
#endif


0

was ist damit?

#ifndef DEBUG_MODE
        fclose(stderr);     // the simplest way to disable output from NSLog
#endif    

1
Dies deaktiviert die Ausgabe, spart aber keine Verarbeitungszeit, dh NSLog wird immer noch aufgerufen und seine Argumente analysiert
dwery

0
var showDebugLogs = false;

    func DLog(format: String, args: CVarArgType...) {
        if showDebugLogs{
        println(String(format: format, arguments: args))
        }
    }

Dies akzeptiert auch die zusätzlichen Argumente. Nur der Parameterwert showDebugLogs wird je nach Bedarf auf true oder false gesetzt


Dies ist nett, hat aber immer noch das Problem des gesamten Aufruf-Overheads und des Overheads (und möglicher Nebenwirkungen) der Berechnung von Argumenten, die an die DlogFunktion übergeben werden.
Todd Lehman
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.