È vero che non si dovrebbe usare NSLog () sul codice di produzione?

Mi è stato detto alcune volte in questo stesso sito, ma volevo assicurarmi che fosse davvero così.

Mi aspettavo di essere in grado di cospargere le chiamate alle funzioni NSLog attraverso il mio codice, e che Xcode / gcc avrebbe automaticamente rimosso quelle chiamate quando costruivo i miei build Release / Distribution.

Dovrei evitare di usare questo? In tal caso, quali sono le alternative più comuni tra i programmatori Objective-C esperti?

Le macro preprocessore sono davvero grandi per il debug. Non c’è niente di sbagliato in NSLog (), ma è semplice definire la propria funzione di registrazione con una migliore funzionalità. Ecco quello che uso, include il nome del file e il numero di riga per rendere più facile rintracciare le dichiarazioni del registro.

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

Ho trovato più facile inserire questa intera istruzione nell’intestazione del prefisso piuttosto che nel proprio file. Potresti, se lo desideri, creare un sistema di registrazione più complicato facendo in modo che DebugLog interagisca con i normali oggetti Objective-C. Ad esempio, potresti avere una class di registrazione che scrive sul proprio file di log (o database) e include un argomento di ‘priorità’ che potresti impostare in fase di runtime, quindi i messaggi di debug non vengono mostrati nella versione di rilascio, ma i messaggi di errore sono ( se lo facessi potresti creare DebugLog (), WarningLog () e così via).

Oh, e tieni presente che #define DEBUG_MODE può essere riutilizzato in diversi punti della tua applicazione. Ad esempio, nella mia applicazione lo uso per disabilitare i controlli delle chiavi di licenza e consentire l’esecuzione dell’applicazione solo se è precedente a una determinata data. Ciò mi consente di distribuire una copia beta completamente funzionale e limitata nel tempo con il minimo sforzo da parte mia.

Metti queste 3 righe alla fine del file -prefix.pch:

 #ifndef DEBUG #define NSLog(...) /* suppress NSLog when in release mode */ #endif 

Non è necessario definire nulla nel progetto, perché DEBUG viene definito nelle impostazioni di generazione per impostazione predefinita quando si crea il progetto.

Le chiamate di NSLog possono essere lasciate nel codice di produzione, ma dovrebbero esserci solo per casi veramente eccezionali o informazioni che si desidera vengano registrate nel registro di sistema.

Le applicazioni che sporcano il registro di sistema sono fastidiose e non sono professionali.

Non posso commentare la risposta di Marc Charbonneau , quindi la posterò come risposta.

Oltre ad aggiungere la macro all’intestazione precompilata, puoi utilizzare le configurazioni di generazione di Target per controllare la definizione (o la mancanza di definizione) del DEBUG_MODE .

Se si seleziona la configurazione triggers ” Debug “, DEBUG_MODE verrà definito e la macro si espande alla definizione NSLog completa.

Selezionando la configurazione triggers di ” Rilascio ” non verrà definito DEBUG_MODE e il NSLog verrà omesso dal build di rilascio.

passi:

  • Target> Ottieni informazioni
  • Scheda Build
  • Cerca “Macro PreProcessor” (o GCC_PREPROCESSOR_DEFINITIONS )
  • Seleziona configurazione: debug
  • Modifica definizione a questo livello
  • Aggiungi DEBUG_MODE=1
  • Seleziona configurazione: rilascia
  • conferma che DEBUG_MODE non è impostato in GCC_PREPROCESSOR_DEFINITIONS

se si omette il carattere ‘=’ nella definizione, si otterrà un errore dal preprocessore

Inoltre, incolla questo commento (mostrato sotto) sopra la definizione della macro per ricordare da dove viene la definizione DEBUG_MACRO 😉

 // Target > Get Info > Build > GCC_PREPROCESSOR_DEFINITIONS // Configuration = Release:  // = Debug: DEBUG_MODE=1 

EDIT: Il metodo pubblicato da Marc Charbonneau , e portato alla mia attenzione da sho , è molto meglio di questo.

Ho eliminato la parte della mia risposta che suggeriva di utilizzare una funzione vuota per disabilitare la registrazione quando la modalità di debug è disabilitata. La parte che riguarda l’impostazione di una macro automatica del preprocessore è ancora rilevante, quindi rimane. Ho anche modificato il nome della macro del preprocessore in modo che si adatti meglio alla risposta di Marc Charbonneau.


Per ottenere il comportamento automatico (e previsto) in Xcode:

Nelle impostazioni del progetto, vai alla scheda “Costruisci” e seleziona la configurazione “Debug”. Trova la sezione “Macro di preprocessore” e aggiungi una macro denominata DEBUG_MODE .

EDIT: vedere la risposta di Marc Charbonneau per il modo corretto di abilitare e disabilitare la registrazione con la macro DEBUG_MODE .

Sono d’accordo con Matthew. Non c’è niente di sbagliato in NSLog nel codice di produzione. In effetti, può essere utile per l’utente. Detto questo, se l’unico motivo per cui stai usando NSLog è quello di aiutare il debug, allora, sì, dovrebbe essere rimosso prima del rilascio.

Inoltre, dal momento che hai taggato questo come una domanda per iPhone, NSLog prende risorse, che è qualcosa che l’iPhone ha poco di prezioso. Se stai registrando su NSL qualcosa sull’iPhone, questo ti porta via il tempo del processore dalla tua app. Usalo saggiamente.

La semplice verità è che NSLog è semplicemente lenta.

Ma perché? Per rispondere a questa domanda, scopriamo cosa fa NSLog e come funziona.

Che cosa fa esattamente NSLog?

NSLog fa 2 cose:

Scrive i messaggi di registro nella funzione Apple System Logging (asl). Ciò consente ai messaggi di log di apparire in Console.app. Controlla inoltre se lo stream stderr dell’applicazione sta andando a un terminale (ad esempio quando l’applicazione viene eseguita tramite Xcode). In tal caso, scrive il messaggio di log su stderr (in modo che venga visualizzato nella console Xcode).

Scrivere su STDERR non sembra difficile. Ciò può essere ottenuto con fprintf e il riferimento del descrittore del file stderr. Ma per quanto riguarda asl?

La migliore documentazione che ho trovato su ASL è un post sul blog in 10 parti di Peter Hosey: link

Senza entrare troppo nel dettaglio, l’evidenziazione (per quanto riguarda le prestazioni) è questa:

Per inviare un messaggio di registro alla funzione ASL, in pratica si apre una connessione client al daemon ASL e si invia il messaggio. MA – ogni thread deve utilizzare una connessione client separata. Quindi, per essere thread-safe, ogni volta che NSLog viene chiamato apre una nuova connessione client asl, invia il messaggio e quindi chiude la connessione.

Le risorse potrebbero essere trovate qui e qui .

Come indicato in altre risposte, è ansible utilizzare un #define per modificare se NSLog è utilizzato o meno in fase di compilazione.

Tuttavia, un modo più flessibile consiste nell’utilizzare una libreria di registrazione come Cocoa Lumberjack che consente di modificare se qualcosa viene registrato anche in fase di esecuzione.

Nel codice sostituire NSLog con DDLogVerbose o DDLogError ecc., Aggiungere un #import per le definizioni macro ecc. E configurare i logger, spesso nel metodo applicationDidFinishLaunching.

Per avere lo stesso effetto di NSLog, il codice di configurazione è

 [DDLog addLogger:[DDASLLogger sharedInstance]]; [DDLog addLogger:[DDTTYLogger sharedInstance]]; 

Dal punto di vista della sicurezza, dipende da cosa viene registrato. Se NSLog (o altri logger) sta scrivendo informazioni sensibili, è necessario rimuovere il registratore nel codice di produzione.

Da un punto di vista del controllo, l’auditor non vuole esaminare ogni utilizzo di NSLog per garantire che non NSLog informazioni riservate. Lui / lei ti dirà semplicemente di rimuovere il registratore.

Lavoro con entrambi i gruppi. Controlliamo il codice, scriviamo le guide di codifica, ecc. La nostra guida richiede che la registrazione sia disabilitata nel codice di produzione. Quindi i team interni sanno di non provarlo;)

Rifiuteremo anche un’app esterna che registra in produzione perché non vogliamo accettare il rischio associato alla perdita accidentale di informazioni sensibili. Non ci interessa ciò che lo sviluppatore ci dice. Semplicemente non vale il nostro tempo per indagare.

E ricorda, definiamo ‘sensibile’, e non lo sviluppatore;)

Percepisco anche un’app che esegue molte registrazioni come un’app pronta per implodere. C’è un motivo per cui viene eseguita / necessaria la registrazione e di solito non è stabile. È proprio lì con i thread “watchdog” che riavviano i servizi appesi.

Se non si è mai passati attraverso una recensione di Security Architecture (SecArch), queste sono le cose che guardiamo.

Non dovresti essere inutilmente prolisso con printf o NSLog nel codice di rilascio. Prova solo a fare un printf o NSLog se l’app ha qualcosa di brutto, ad esempio un errore irrecuperabile.

Tieni presente che NSLogs può rallentare l’interfaccia utente / thread principale. È meglio rimuoverli dalle build di rilascio a meno che non sia assolutamente necessario.

Consiglio vivamente di utilizzare TestFlight per la registrazione (gratuita). Il loro metodo sovrascrive NSLog (utilizzando una macro) e consente di triggersre / distriggersre la registrazione sul loro server, il registro del sistema Apple e il registro STDERR, per tutte le chiamate esistenti verso NSLog. La cosa bella di questo è che puoi ancora controllare i tuoi messaggi di log per le app distribuite ai tester e alle app distribuite nell’App Store, senza che i registri compaiano sul log di sistema dell’utente. Il meglio dei due mondi.