Entfernen Sie println () für die Release-Version iOS Swift


83

Ich möchte alle println()Aufrufe in meinem Swift-Code global ignorieren, wenn ich mich nicht in einem Debug-Build befinde. Ich kann keine robuste Schritt-für-Schritt-Anleitung dafür finden und würde mich über eine Anleitung freuen. Gibt es eine Möglichkeit, dies global zu tun, oder muss ich alle println()mit #IF DEBUG/#ENDIFAussagen umgeben?



6
Der Druck wird nicht mehr in der Gerätekonsole ausgegeben, sondern in der Debugger-Konsole. Daher muss er für die Release-Version nicht entfernt werden.
Anish Parajuli 11

1
Ab Xcode 8 und Swift 3 werden im Release-Modus keine Ausdrucke in der Konsole angezeigt.
CiNN

Antworten:


99

Der einfachste Weg ist, Ihre eigene globale Funktion vor die von Swift zu stellen println:

func println(object: Any) {
    Swift.println(object)
}

Wenn es Zeit ist, die Protokollierung zu beenden, kommentieren Sie einfach den Hauptteil dieser Funktion aus:

func println(object: Any) {
    // Swift.println(object)
}

Oder Sie können es automatisch machen, indem Sie eine Bedingung verwenden:

func println(object: Any) {
    #if DEBUG
        Swift.println(object)
    #endif
}

BEARBEITEN In Swift 2.0 printlnwird in geändert print. Leider hat es jetzt einen variadischen ersten Parameter; Das ist cool, aber es bedeutet, dass Sie es nicht einfach überschreiben können, da Swift keinen "splat" -Operator hat, sodass Sie keine Variable im Code übergeben können (sie kann nur wörtlich erstellt werden). Sie können jedoch eine reduzierte Version erstellen, die funktioniert, wenn Sie wie gewöhnlich nur einen Wert drucken:

func print(items: Any..., separator: String = " ", terminator: String = "\n") {
    Swift.print(items[0], separator:separator, terminator: terminator)
}

In Swift 3 müssen Sie die externe Bezeichnung des ersten Parameters unterdrücken:

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    Swift.print(items[0], separator:separator, terminator: terminator)
}

3
Gute Lösung, danke. Mir wurde gesagt, dass in iOS (aber nicht in OS X) println()nicht im Release-Modus ausgeführt wird.
Nate Birkholz

12
@NateBirkholz Nein, das ist Unsinn. (Sagte er nach dem Testen, um sicherzugehen!)
matt

Würden Sie in Swift 2 mit der in Drucken umbenannten Funktion nur die Chance haben, dass die Funktion übereinstimmt? Wie würden Sie dies auch global definieren? Ich habe versucht, es außerhalb meiner Klasse in AppDelegate zu platzieren, und es wird nie aufgerufen, obwohl ich eine Million print () -Aufrufe habe. Folgendes habe ich versucht: func print (Objekt: Beliebig) {Swift.print (Objekt)}
Charlie

@Charlie Ja, ich benutze es immer noch mit printlngeändert aufprint . Der Grund, warum es bei Ihnen nicht funktioniert, ist, dass Ihre printDefinition nicht mit der von Swift übereinstimmt, sodass Sie sie nicht überschreiben. Es gibt ein kleines Problem, da Swift, wie schon oft bemerkt, keinen Splat-Operator hat, sodass Sie die Variadik nicht übergeben können. Aber es funktioniert gut für einen Artikel, den Sie als übergeben können items[0].
Matt

2
Eine Einschränkung hier, wenn Sie diese Protokollanweisungen in leistungsstarke Codeabschnitte einfügen: Swift wird weiterhin Zeit mit der Interpolation von Zeichenfolgen und dem Rendern von Parametern verbringen, um diese an die Funktion zu übergeben, auch wenn sie nicht verwendet werden. Die einzige Möglichkeit, die Anweisungen wirklich bedingt zu entfernen, besteht darin, sie auf einem Flag zu prädizieren. zB if (log) {print (..)} an jedem Ort, an dem sie verwendet werden.
Pat Niemeyer

46

Aktualisiert für Swift 4.x:

Mit Swift 2.0 / 3.0 und Xcode 7/8, die jetzt nicht mehr in der Beta sind, wurden einige Änderungen an der Deaktivierung der Druckfunktion in Release-Builds vorgenommen.

Es gibt einige wichtige Punkte, die von @matt und @Nate Birkholz oben erwähnt wurden und die noch gültig sind.

  1. Die println()Funktion wurde ersetzt durchprint()

  2. Um das #if DEBUG Makro zu verwenden, müssen Sie den "Swift Compiler - Benutzerdefinierte Flags - Andere Flags" definieren, um den Wert zu enthalten-D DEBUG

  3. Ich würde empfehlen, das zu überschreiben Swift.print() Funktion im globalen Bereich zu damit Sie die print()Funktion wie gewohnt in Ihrem Code verwenden können, aber die Ausgabe für Nicht-Debug-Builds wird entfernt. Hier ist eine Funktionssignatur, die Sie im globalen Bereich hinzufügen können, um dies in Swift 2.0 / 3.0 zu tun:

    func print(items: Any..., separator: String = " ", terminator: String = "\n") {
    
        #if DEBUG
    
        var idx = items.startIndex
        let endIdx = items.endIndex
    
        repeat {
            Swift.print(items[idx], separator: separator, terminator: idx == (endIdx - 1) ? terminator : separator)
            idx += 1
        }
        while idx < endIdx
    
        #endif
    }

Hinweis: Wir haben das Standardtrennzeichen hier als Leerzeichen und das Standardterminator als Zeilenumbruch festgelegt. Sie können dies in Ihrem Projekt anders konfigurieren, wenn Sie möchten.

Hoffe das hilft.

Aktualisieren:

Es ist normalerweise vorzuziehen, diese Funktion in den globalen Bereich zu stellen, damit sie vor Swifts printFunktion steht. Ich finde, dass der beste Weg, dies zu organisieren, darin besteht, Ihrem Projekt eine Dienstprogrammdatei (wie DebugOptions.Swift) hinzuzufügen, in der Sie diese Funktion im globalen Bereich platzieren können.

Ab Swift 3 ist der ++Bediener veraltet. Ich habe das obige Snippet aktualisiert, um diese Änderung widerzuspiegeln.


1
Es tut mir leid, aber wo soll die Funktion platziert werden?
DàChún

@ User9527 Wahrscheinlich möchten Sie dies irgendwo in den globalen Bereich stellen, damit es während Ihres gesamten Projekts zugänglich ist. In meinen Projekten füge ich eine Dienstprogramm-Swift-Datei (DebugOptions.swift oder ähnliches) hinzu und platziere diese Funktion im globalen Bereich (dh nicht in einer eingeschlossenen Klasse).
Glavid

Können Sie bestätigen, dass ab der aktuellen Version von Swift-Xcode die print-Anweisung nicht mehr an die Gerätekonsole ausgegeben wird, ohne dass das -D-Debug flach eingestellt werden muss? Zumindest habe ich das heute getestet.
user523234

1
Ab Swift 3 kann man etwas mehr Kürze erreichen, indem man am Anfang der Liste der Argumente einen Unterstrich hinzufügt: "print (_ items ..."
Jonathan Zhan

7
Also habe ich die Referenz des Drucks nachgeschlagen (verwendet in didFinishLaunching ...) und sie hat mich auf die ursprüngliche Druckfunktion Swift hingewiesen. Wenn ich das und den Kommentar von @ JonathanZhan zusammenstelle, habe ich die Funktion so angepasst, dass sie so aussieht und voila es funktioniert:public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
Jonny

37

Das Problem bei all diesen Ansätzen, einschließlich meiner, besteht darin, dass sie den Aufwand für die Bewertung der printArgumente nicht verringern . Egal welche von ihnen Sie verwenden, dies wird teuer:

print(myExpensiveFunction())

Die einzig vernünftige Lösung besteht darin, den eigentlichen Druckaufruf in eine bedingte Kompilierung zu verpacken (nehmen wir an, dass dies DEBUGnur für Debug-Builds definiert ist):

#if DEBUG
print(myExpensiveFunction())
#endif

Das und nur das verhindert, dass myExpensiveFunctiones in einem Release-Build aufgerufen wird.

Sie können die Auswertung jedoch mithilfe der automatischen Schließung um eine Ebene zurückschieben . So können Sie meine Lösung (dies ist Swift 3) folgendermaßen umschreiben:

func print(_ item: @autoclosure () -> Any, separator: String = " ", terminator: String = "\n") {
    #if DEBUG
    Swift.print(item(), separator: separator, terminator: terminator)
    #endif
}

Dies löst das Problem nur für den Fall, dass Sie nur eine Sache drucken, was normalerweise zutrifft. Das liegt daran item(), dass im Release-Modus nicht aufgerufen wird. print(myExpensiveFunction())Dies ist nicht mehr teuer, da der Anruf ohne Auswertung in einen Abschluss eingeschlossen wird und im Freigabemodus überhaupt nicht ausgewertet wird.


Was nützt das @autoclosure?
Kelin

@matt in Ihrem Buch erwähnen Sie "Ein wichtiges Merkmal des Drucks ist, dass es effektiv unterdrückt wird, wenn die App unabhängig von Xcode gestartet wird". Bedeutet dies, dass wir unsere Druckaussagen heutzutage in unseren eingereichten Apps belassen können, oder verstehe ich das falsch? etwas?
versteckter Benutzername

@ hidden-username Ja, ich neige dazu, meine printAussagen in meinem Versandcode zu belassen, aber das unterscheidet sich von dem, worum es in meiner Antwort hier geht. Eine printAnweisungsausgabe wird in Ihrem Xcode-unabhängigen Release-Build nicht an die Konsole gesendet, sie wird jedoch weiterhin ausgewertet . Daher bleibt es hilfreich zu wissen, wie diese Auswertung unterdrückt werden kann, falls sie teuer ist oder unerwünschte Nebenwirkungen aufweist.
Matt

@matt oh ok ... Ja, ich habe es falsch verstanden. Ich werde sie auskommentieren. Danke
versteckter Benutzername

Wird dieser Ansatz die gedruckte Zeichenfolge aus der Binärdatei entfernen? Wenn ich zum Beispiel diese Methode verwendet habe und irgendwo in meiner App "print (" Benutzer angemeldet ")" eingefügt habe und wenn jemand versucht, meine App zurückzuentwickeln, findet er diese Zeichenfolge irgendwo oder ist sie überhaupt nicht vorhanden?
Leszek Szary

17

Wie bereits erwähnt, bin ich Student und brauche Dinge, die etwas klarer definiert sind, um mitzumachen. Nach vielen Recherchen musste ich folgende Reihenfolge einhalten:

Klicken Sie oben im Datei-Navigator links im Xcode-Projektfenster auf den Projektnamen. Dies ist eine Zeile mit dem Namen des Projekts, der Anzahl der Build-Ziele und der iOS SDK-Version.

Wählen Sie die Registerkarte Build Settings und scrollen Sie zum Abschnitt " Swift Compiler - Custom Flags " unten. Klicken Sie auf den Abwärtspfeil neben Andere Flags , um den Abschnitt zu erweitern.

Klicken Sie auf die Debug- Zeile, um sie auszuwählen. Platzieren Sie den Mauszeiger über der rechten Seite der Linie und doppelklicken Sie. Eine Listenansicht wird angezeigt. Klicken Sie unten links in der Listenansicht auf die Schaltfläche + , um einen Wert hinzuzufügen. Ein Textfeld wird aktiv.

Geben Sie im Textfeld den Text ein -D DEBUGund drücken Sie die Eingabetaste , um die Zeile festzuschreiben.

Fügen Sie Ihrem Projekt eine neue Swift-Datei hinzu. Sie möchten eine benutzerdefinierte Klasse für die Datei erstellen. Geben Sie daher Text wie folgt ein:

class Log {

  var intFor : Int

  init() {
    intFor = 42
   }

  func DLog(message: String, function: String = __FUNCTION__) {
    #if DEBUG
      println("\(function): \(message)")
    #endif
  }
}

Ich hatte Probleme, die Klasse heute von Xcode zu akzeptieren, daher ist der Init möglicherweise etwas schwerer als nötig.

Jetzt müssen Sie Ihre benutzerdefinierte Klasse in jeder Klasse referenzieren, in der Sie die neue benutzerdefinierte Funktion anstelle von println()Add this als Eigenschaft in jeder anwendbaren Klasse verwenden möchten:

   let logFor = Log()

Jetzt können Sie alle Instanzen von println()durch ersetzenlogFor.DLog() . Die Ausgabe enthält auch den Namen der Funktion, in der die Zeile aufgerufen wurde.

Beachten Sie, dass ich innerhalb von Klassenfunktionen die Funktion nur aufrufen konnte, wenn ich eine Kopie der Funktion als Klassenfunktion in dieser Klasse erstellt habe, und dass println()die Eingabe auch etwas flexibler ist, sodass ich sie nicht in jedem Fall in verwenden konnte mein Code.


7
Es ist nicht erforderlich, eine benutzerdefinierte Klasse für das Debug-Protokoll zu erstellen. Es ist einfacher und praktischer, eine globale Funktion zu verwenden.
Vojtech Vrbka

Was ist die Verwendung von intFor = 42?
Ted

11

Hier ist eine Funktion, die ich benutze und die in Swift 3 perfekt funktioniert:

func gLog<T>( _ object: @autoclosure() -> T, _ file: String = #file, _ function: String = #function, _ line: Int = #line)
    {
    #if DEBUG
        let value = object()
        let stringRepresentation: String

        if let value = value as? CustomDebugStringConvertible
            {
            stringRepresentation = value.debugDescription
            }
        else if let value = value as? CustomStringConvertible
            {
            stringRepresentation = value.description
            }
        else
            {
            fatalError("gLog only works for values that conform to CustomDebugStringConvertible or CustomStringConvertible")
            }

        let fileURL = NSURL(string: file)?.lastPathComponent ?? "Unknown file"
        let queue = Thread.isMainThread ? "UI" : "BG"
    let gFormatter = DateFormatter()
    gFormatter.dateFormat = "HH:mm:ss:SSS"
        let timestamp = gFormatter.string(from: Date())

        print("✅ \(timestamp) {\(queue)} \(fileURL) > \(function)[\(line)]: " + stringRepresentation + "\n")
    #endif
    }

Hier ist ein Beispiel für die Ausgabe, die es generiert:

Screenshot der Ausgabe

Erläuterung:

  • Mit dem grünen Häkchen können Sie Ihre Drucknachrichten (gLog) schnell in der Konsole anzeigen, wo sie manchmal in einem Meer anderer Nachrichten verloren gehen können

  • den Zeit- / Datumsstempel

  • der Thread, auf dem es ausgeführt wird - in meinem Fall ist es entweder der MainThread (den ich UI nenne) oder nicht der MainThread (den ich BG nenne, für den Hintergrund-Thread)

  • Der Name der Datei, in der sich die gLog-Nachricht befindet

  • Die Funktion in der Datei, in der sich die gLog-Nachricht befindet

  • die Zeilennummer der gLog-Nachricht

  • Die eigentliche gLog-Nachricht, die Sie ausdrucken möchten

Hoffe, das ist nützlich für jemand anderen!


Kann dies in eine separate Datei gestellt werden, die in der gesamten App verwendet werden kann? Ich habe versucht, es als Klassenmethode in eine separate Klassendatei zu schreiben. Es stürzt jedoch mit libMobileGestalt ab. MobileGestaltSupport.m: 153: pid 2574 (Demo) hat keinen Sandbox-Zugriff für frZQaeyWLUvLjeuEK43hmg und ist NICHT entsprechend libMobileGestalt MobileGestalt.c: 550: Kein Zugriff auf InverseDeviceID (siehe <rdar: // problem / 11744455) ) Nachricht vom Debugger:
Beendet

omarojo, ich benutze dies als globale Funktion in meiner App. Es ist keine Klasse erforderlich. Ich habe eine Datei mit dem Namen utils.swift, die alle meine Dienstprogrammfunktionen wie diese enthält. Sie müssen nur sicherstellen, dass Sie Foundation importieren - vielleicht ist dies der Schritt, den Sie verpasst haben? Weitere Informationen zum Deklarieren Ihrer Funktionen innerhalb von Klassen, als statische Funktionen innerhalb von Klassen oder als globale Funktionen finden Sie in dieser SO-Frage und den Antworten: stackoverflow.com/questions/30197548/…
Gene Loparco,

Ja, es hat funktioniert, indem Sie einfach eine neue Datei mit der darin enthaltenen Funktion erstellt haben. Aus irgendeinem Grund würde die App als Klassenfunktion ohne eindeutige Debug-Meldung abstürzen.
Omarojo

Danke für diesen Mann, schade, dass ich es vorher nicht entdeckt habe. Ersparte mir viel Kopfschmerzen beim Debuggen.
Beowulf

Es ist mir ein Vergnügen @beowulf!
Gene Loparco

11

Swift 4.2

Der folgende Code funktioniert perfekt für mich:

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    #if DEBUG
    items.forEach {
        Swift.print($0, separator: separator, terminator: terminator)        
    }
    #endif
}

Diese Funktion spiegelt den Standard-Swift-Druck wider, sodass Sie ihn genauso verwenden können print("hello world")(Sie müssen weder die Trennzeichen- noch die Abschlusszeichenparameter eingeben). Durch das Drucken jedes Elements auf diese Weise werden außerdem störende Array-Klammern um die Druckanweisungen entfernt, die angezeigt werden, wenn Sie direkt itemsin das Element übergehen Swift.print().

Für jemanden, der relativ neu in Swift ist, mag man sich fragen, was zum Teufel $0 ist. Es stellt nur das erste Argument dar, das an den forEachBlock übergeben wird. Die forEachAussage könnte auch so geschrieben werden:

items.forEach { item in
    Swift.print(item, separator: separator, terminator: terminator)        
}

Wenn Sie interessiert sind, printsieht die Swift-Erklärung folgendermaßen aus :

public func print(_ items: Any..., separator: String = default, terminator: String = default)

Die Dokumente sagen auch, dass das Standardtrennzeichen ein einzelnes Leerzeichen ( " ") und das Standardterminator ein Zeilenumbruch ( "\n") ist, sodass meine obige Antwort die genaue Swift-Implementierung widerspiegelt - obwohl ich nie mehr als eine Sache drucke oder Trennzeichen / Terminatoren ändere. Aber wer weiß, vielleicht möchten Sie.


1
Wo soll diese Funktion deklariert werden? Ist dies eine Erweiterung oder eine solche? Ich möchte es einfach nicht in jeder Datei deklarieren)
Matrosov Alexander

1
@MatrosovAlexander Sie können einfach eine schnelle Datei an einer beliebigen Stelle in Ihrem App-Projekt erstellen und diesen Code einfügen. Der Compiler ist intelligent genug, um ihn global zugänglich zu machen.
Trev14

9

Getestet mit Swift 2.1 & Xcode 7.1.1

Es gibt eine einfache Möglichkeit, alle Druckanweisungen von Release-Versionen auszuschließen, sobald Sie wissen, dass leere Funktionen vom Swift-Compiler entfernt werden .

Randnotiz: In der Ära von Objective-C gab es einen Pre-Parser, mit dem NSLog-Anweisungen vor dem Start des Compilers entfernt werden konnten, wie in meiner Antwort hier beschrieben . Da Swift jedoch keinen Pre-Parser mehr hat, ist dieser Ansatz nicht mehr gültig.

Folgendes verwende ich heute als erweiterte und einfach konfigurierbare Protokollfunktion, ohne mich jemals darum kümmern zu müssen, sie in Release-Builds zu entfernen. Durch Setzen verschiedener Compiler-Flags können Sie auch die protokollierten Informationen nach Bedarf anpassen.

Sie können die Funktion nach Bedarf anpassen. Jeder Vorschlag zur Verbesserung ist willkommen!

// Gobal log() function
//
// note that empty functions are removed by the Swift compiler -> use #if $endif to enclose all the code inside the log()
// these log() statements therefore do not need to be removed in the release build !
//
// to enable logging
//
// Project -> Build Settings -> Swift Compiler - Custom flags -> Other Swift flags -> Debug
// add one of these 3 possible combinations :
//
//      -D kLOG_ENABLE
//      -D kLOG_ENABLE -D kLOG_DETAILS
//      -D kLOG_ENABLE -D kLOG_DETAILS -D kLOG_THREADS
//
// you can just call log() anywhere in the code, or add a message like log("hello")
//
func log(message: String = "", filePath: String = #file, line: Int = #line, function: String = #function) {
            #if kLOG_ENABLE

            #if kLOG_DETAILS

            var threadName = ""
            #if kLOG_THREADS
                threadName = NSThread.currentThread().isMainThread ? "MAIN THREAD" : (NSThread.currentThread().name ?? "UNKNOWN THREAD")
                threadName = "[" + threadName + "] "
            #endif

            let fileName = NSURL(fileURLWithPath: filePath).URLByDeletingPathExtension?.lastPathComponent ?? "???"

            var msg = ""
            if message != "" {
                msg = " - \(message)"
            }

            NSLog("-- " + threadName + fileName + "(\(line))" + " -> " + function + msg)
        #else
            NSLog(message)
        #endif
    #endif
}

Hier setzen Sie die Compiler-Flags:

Geben Sie hier die Bildbeschreibung ein

Eine Beispielausgabe mit allen Flags sieht folgendermaßen aus:

   2016-01-13 23:48:38.026 FoodTracker[48735:4147607] -- [MAIN THREAD] ViewController(19) -> viewDidLoad() - hello

Der Code mit log () sieht folgendermaßen aus:

    override func viewDidLoad() { log("hello")
    super.viewDidLoad()

   // Handle the text field's user input through delegate callbacks
   nameTextField.delegate = self
}

Schön! Ich nahm es von hier und machte schließlich AELog und AEConsole .
Tadija

Dies funktioniert im DEBUG-Modus einwandfrei. Jetzt habe ich vom Bearbeitungsschema in den RELEASE-Modus gewechselt. Es zeigt auch das Anmeldekonsolenfenster für den Freigabemodus. Warum so?
Jayprakash Dubey

Für Swift 3.2 in Xcode 9 musste ich NSLog so ändern, dass es mit log druckt und aufruft (Nachricht: "Hallo"). Außerdem musste ich die Flags als "-D" "kLOG_ENABLE" mit den Anführungszeichen einfügen. Alle anderen schnellen Versionsaktualisierungen wurden vom Compiler mit vorgeschlagenen Korrekturen übernommen.
iCyberPaul

1
Hier geben Sie an, dass "leere Funktionen vom Swift-Compiler entfernt werden". Wo finden wir das in den Dokumenten? Woher wissen Sie, dass dies der Fall ist? @ ronny-webers
zumzum

7

Noch einfacher, nachdem Sie sichergestellt haben -D DEBUG, dass die OTHER_SWIFT_FLAGSDebug-Build-Einstellungen festgelegt sind:

#if !DEBUG
    func print(_ items: Any..., separator: String = " ", terminator: String = "\n") { }
#endif

Ich vermute, dass dies ein "Wo" erfordert, da druckbare Objekte einem der Systemprotokolle entsprechen, die Sie selten in Videos für wwdc erwähnt sehen, und ich denke, am Ende der schnellen Anleitung (en) 1.2 vs 2 haben Sie den Unterschied vergessen, wenn es sie gibt ist eins mit dem System eins
Stephen J

Bisher funktioniert dies mit Swift 1.2. Ich habe 2.0 nicht ausprobiert.
Rivera

6

XCode 8 hat einige neue Build-Einstellungen eingeführt .
Insbesondere macht einer, auf den Bezug genommen wird, Active Compilation Conditionsauf ähnliche Weise wie die Einstellungen für andere Flags .

"Active Compilation Conditions" ist eine neue Build-Einstellung zum Übergeben von Flags für bedingte Kompilierungen an den Swift-Compiler.

Gemäß XCode 8 (getestet in 8.3.2) erhalten Sie dies standardmäßig:

Geben Sie hier die Bildbeschreibung ein

Ohne Konfiguration können Sie also Folgendes schreiben:

#if DEBUG
    print("⚠️ Something weird happened")
#endif

Ich empfehle Ihnen dringend, wenn Sie diesen Ansatz ausgiebig verwenden, eine Klasse / Struktur / Funktion zu erstellen, die diese Protokollierungslogik umschließt. Vielleicht möchten Sie dies weiter unten verlängern.


4

Varun Naharia hat bisher die bessere Lösung. Ich würde seine Antwort mit Riveras ...

  1. Erstellen Sie ein -D DEBUGFlag in den Compiler-Direktiven und erstellen Sie Einstellungen.
  2. Fügen Sie dann diesen Code hinzu:

    #if !DEBUG
     public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    }
    #endif

Dieser Code wandelt alles printzur Veröffentlichung in nichts um.


3

Swift 4 Xcode 10.0

Vielleicht könntest du das gebrauchen

func dPrint(_ message: @autoclosure () -> Any) {
    #if DEBUG
    print(message())
    #endif
}

Der Grund der Verwendung @autoclosure ist, dass, wenn Sie eine Funktion als Nachrichtenparameter übergeben, die Funktion nur im Debug-Modus aufgerufen wird und einen Leistungseinbruch verursacht.

Im Gegensatz zur Swift.print(_ items: Any..., separator: String = default, terminator: String = default)Funktion hat meine Lösung nur einen Parameter, da in den meisten Fällen nicht mehrere Parameter übergeben werden, da die Druckfunktion nur Informationen in der Konsole anzeigt. Wir können die Parameter einfach in String konvertieren : "\(param1)"+"\(param2)", richtig? Ich hoffe du magst meine Lösung


1

Sie können auch einen Haltepunkt verwenden, ihn so einstellen, dass er nach der Auswertung fortgesetzt wird, und die Drucknachricht in den Haltepunkt schreiben!

Geben Sie hier die Bildbeschreibung ein


0

Sie könnten definieren, debug_printlnwessen Inhalt ungefähr sein würde:

#if DEBUG
  println()
#endif

Danke, wo könnte ich es am besten definieren? Ich bin ein Student, fürchte ich, und ich schätze die Hilfe sehr, benötige aber einen expliziteren Kontext.
Nate Birkholz

Sie würden es in einer Header-Datei deklarieren, die Sie an eine beliebige Stelle importieren würden, an der Sie es verwenden möchten.
Ian MacDonald

0

Meine Lösung besteht darin, diesen Code vor dem Unterricht in AppDelegate zu verwenden

// Disable console log in live app
#if !arch(x86_64) && !arch(i386)
    public func debugPrint(items: Any..., separator: String = " ", terminator: String = "\n") {

    }
    public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {

    }
#endif

class AppDelegate: UIResponder, UIApplicationDelegate {
// App Delegate Code 

}

0

Für meine Lösung mache ich es einfach

import UIKit

class DLog: NSObject {

   init(title:String, log:Any) {
       #if DEBUG
           print(title, log)
       #endif

   }

}

dann, um es zu zeigen, rufen Sie einfach an

_ = DLog(title:"any title", log:Any)

0

Am Ende habe ich Folgendes verwendet:

#if DEBUG
func dLog(_ item: @autoclosure () -> Any, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
    print("\(Date()) [\((file as NSString).lastPathComponent):\(line) \(function)] \(item())")
}
#else
func dLog(_ item: @autoclosure () -> Any) {}
#endif

Es ist ziemlich kompakt, druckt einige nützliche Informationen (Zeitstempel, schneller Dateiname, Codezeile, Funktionsname) und zumindest in meinen Tests konnte ich beim Öffnen im Hex-Editor keine protokollierten Zeichenfolgen in der Anwendungsbinärdatei finden.


0

Noch einfacher: Nutzen Sie die Tatsache, dass Asserts aus Release-Builds entfernt werden und nur von dort aus den Druck aufrufen. Dadurch werden alle Protokollaufrufe entfernt (ja, sogar die Aufrufe von Log.da), da sie beim Erstellen für die Freigabe leer sind.

Ich habe aber auch gehört, dass Ausdrucke für Release-Builds entfernt werden, konnte sie aber nicht schriftlich finden. Im Moment verwende ich so etwas Logunten. Ich habe eine fleischigere Version auf GitHub mit Emojis (aus Gründen der Lesbarkeit) und Protokollthemen (aus Gründen der Konsistenz):

https://github.com/Gatada/JBits/blob/master/Project/Utility/Log.swift

public enum Log {

    /// A date formatter used to create the timestamp in the log.
    ///
    /// This formatter is only created if it is actually used, reducing the
    /// overhead to zero.
    static var formatter: DateFormatter?

    // MARK: - API

    /// Call to print message in debug area.
    ///
    /// Asserts are removed in release builds, which make
    /// the function body empty, which caused all calls to
    /// be removed as well.
    ///
    /// Result is zero overhead for release builds.
    public static func da(_ message: String) {
        assert(debugAreaPrint(message))
    }

    // MARK: - Helpers

    /// The function that actually does the printing. It returns `true` to
    /// prevent the assert from kicking in on debug builds.
    private static func debugAreaPrint(_ message: String) -> Bool {
        print("\(timestamp) - \(message)")
        return true
    }

    /// Creates a timestamp used as part of the temporary logging in the debug area.
    static private var timestamp: String {

        if formatter == nil {
            formatter = DateFormatter()
            formatter!.dateFormat = "HH:mm:ss.SSS"
        }

        let date = Date()
        return formatter!.string(from: date)
    }
}

In Code:

Log.da("This is only handled in a debug build.")

Gesehen in dem Xcode Debug - Bereich nur , wenn ein Debug - Build ausgeführt wird :

13: 36: 15.047 - Dies wird nur in einem Debug-Build behandelt.


0

Mein Projekt wurde in Ziel C entwickelt, aber seit dem letzten Jahr habe ich begonnen, neuen Code in Swift zusammenzuführen. In der folgenden Swift-Lösung habe ich diesen Code in die konstante Datei "Mein Swift" eingefügt:

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    #if DEBUG
    items.forEach {
        Swift.print($0, separator: separator, terminator: terminator)
    }
    #endif
}
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.