Articoli con Tag ‘NSLog()’

Objective-C: NSLog() su struct C

La sintassi NSLog(@"%@", ... ); funziona ed è utilizzata per ottenere informazioni sugli oggetti, ma non funziona su tipi dato C come struct CGRect o CGPoint, ad esempio. Per poter sfruttare NSLog(@"%@", ... ); anche su struct di tipo C possiamo appoggiarci a funzioni di conversione come NSStringFromCGRect() o NSStringFromCGPoint:

1
2
3
4
5
CGrect mioRect = (CGRect){10,20,30,40};
CGPoint mioPoint = (CGPoint){32,64};
//
NSLog( @"Info rettangolo: %@", NSStringFromCGRect(mioRect) );
NSLog( @"Info point: %@", NSStringFromCGPoint(mioPoint) );

Nello specifico è possibile perfezionare tale procedure scrivendosi delle piccole macro utili come:

1
#define NSLogRect(rect) NSLog(@"%s: (%0.0f, %0.0f) %0.0f x %0.0f", #rect, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)

Oppure:

1
2
3
4
#define NSLogCGPoint(point) NSLog(@"%s: (%0.0f, %0.0f)", #point point.x, point.y)

CGPoint mioPoint = (CGPoint){32,64};
NSLogCGPoint(mioPoint);

Che darà come output:

1
mioPoint: (32, 64)

Continua...

Come eliminare NSLog() dai sorgenti XCode

<a target="_blank" href="http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/func/NSLog">NSLog()</a> è una funzione utilissima durante le fasi iniziali di un progetto, per il testing e il debug di un’applicazione per Apple iPhone o, più in generale, in ambiente XCode. Essendo appunto una funzione, esattamente come le altre, la sua presenza si farà sentire anche quando rilasceremo (release) il nostro eseguibile. Diventa quindi necessario rimuovere, in qualche modo, tutte le righe di NSLog() dal nostro codice, sia perchè non più necessarie, sia perchè le chiamate a NSLog() potrebbero influire sulle performance della nostra applicazione, soprattutto se abbiamo inserito NSLog() all’interno di loop.

Escludiamo subito la soluzione del “cerca” ed “elimina”; perchè un domani ci potrebbero servire nuovamente. Escludiamo anche la soluzione del “cerca” e “commenta”, scomoda per lo stesso motivo di prima. Fortunatamente una soluzione pulita, semplice e corretta la troviamo sfruttando le istruzioni condizionali del compilatore. Quello che faremo, in pratica, e dire al compilatore di escludere – se si verifica una determinata condizione – durante la compilazione del nostro sorgente le righe che contengono NSLog().

Le direttive di compilazioni e le istruzioni condizionali del compilatore, sono uno strumento molto potente e diffuso. Chi proviene dallo sviluppo ANSI-C le conosce sicuramente molto bene e le avrà utilizzte in moltissime situazioni. La particolarità di queste “istruzioni” risiede nel fatto, sopra accennato, di essere viste dal compilatore e non dall’eseguibile. Questa loro caratteristica le rende utili in moltissimi casi e permette di risolvere problematiche altrimenti assai fastidiose.

Vediamo subito un esempio di codice che, come preannunciato, permette di “eliminare” dalla compilazione parti di codice, nel nostro caso NSLog():

1
2
3
4
5
6
#define ACTIVE_NSLOG 1
// se la costante ACTIVE_NSLOG è definita compila
// il blocco di codice compreso tra #ifdef e #endif
#ifdef ACTIVE_NSLOG
    NSLog( @" ... bla bla" );
#endif

Le istruzioni condizionali del compilatore fanno parte della stessa famiglia della #define; anch’esse, infatti, sono precedute dal carattere “cancelletto” (#). Nell’esempio mostrato abbiamo definito una costante ACTIVE_NSLOG; le successive righe di codice dicono al compilatore di “includere” la riga NSLog() solo se ACTIVE_NSLOG è definito. Se abbiamo avuto la cura, durante la stesura del nostro codice, di inserire le chiamate a NSLog() all’interno del blocco #ifdef ... #endif, basterà eliminare la definizione della costante ACTIVE_NSLOG per far sparire, alla prossima compilazione, tutti i nostri NSLog().

Una soluzione migliore e definitiva

Vediamo adesso come impostare l’ambiente XCode per migliorare ancor di più ciò che abbiamo fatto sopra! Prima di tutto scegliamo un nome di costante che useremo nei nostri progetti per escludere dalla compilazione NSLog(). Potete scegliere il nome che più vi piace, da DEBUG a MIO_DEBUG o quello che preferite. Aprite il vostro progetto, nuovo o vecchio. Inserite tutti gli NSLog() all’interno del blocco (o di un blocco):

1
2
3
#ifdef MIO_DEBUG
    NSLog( @" ... bla bla" );
#endif

Selezionate il file principale del vostro progetto, cliccate con il tasto destro e scegliete la voce Get Info.

getinfo

Si aprira la finestra con le informazioni sul progetto:

userdefine

Selezionate la scheda Build, verificate di essere in configurazione Debug (è questa la chicca), andate nella sezione User-Defined e aggiungete, tramite il bottone in basso a sinistra, un nuovo campo chiamato OTHER_CFLAGS. A questo assegnamoli il valore -DMIO_DEBUG=1. La sintassi è -D{mia define}=1.

Questa procedura ha due vantaggi:

  1. Non dobbiamo inserire nel codice la #define MIO_DEBUG 1, ma lo facciamo tramite le informazioni sul progetto. Quindi, quando andremo a compilare la versione di rilascio (quella senza gli NSLog()) non dobbiamo ricordarci di eliminare la riga #define MIO_DEBUG 1
  2. La costante è definita in relazione alla configurazione, nel nostro caso Debug. Quindi, passando alla configurazione di rilascio (release) la costante sarà assente e le righe con NSLog() non verranno compilate

Conclusioni

La procedura sopra descritta può essere utile in una moltidutine di altri casi che, con NSLog(), non hanno nulla a che fare. Le istruzioni condizionali del compilatore possono aiutarci in una vastissima gamma di contesti. Spesso sono utilizzate dai programmatori per determinare il tipo di sistema operativo, la versione, il target, la presenza di processori matematici, mantenendo uno stesso “identico” sorgente.

Per capirci, come esempio, possiamo utilizzre la nostra costante MIO_DEBUG anche per intervenire in altre zone del codice:

1
2
3
4
5
6
7
8
9
10
// se sono in debug vinco la partita
// con uno score di 100 invece che di 10000 :)
#ifdef MIO_DEBUG
    if( score == 100 )
#else
    if( score == 10000 )
#endif
    {
        [self haiVinto];
    }

Per completare, ecco alcuni esempi e varianti:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// più in generale esiste la
#if espressione
// simile alle if tradizionali, quindi con una espressione completa

// verifica se è definita una costante
#ifdef costante

// verifica se NON è definita una costante
#ifndef costante

// else
#else

// chiusura del blocco
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ad esempio...
#define DEBUG 1
#define MIA_ALTRA_COSTANTE 5
 
...
#if DEBUG
  // compila questo
#else
  // altrimenti compila quest'altro
#endif
 
#if MIA_ALTRA_COSTANTE > 4
  NSLog(@"...");
#endif
1
2
3
4
#ifndef INCLUDE_MIO_FILE
    #define INCLUDE_MIO_FILE
    #include "mio_file.h"
#endif

Continua...

Actionscript trace, Objective-C NSLog()

Riprendendo il post Da Actionscript ad Objective-C (dove si mettevano a confronto il codice e la sintassi Actionscript e Objective-C), in Actionscript abbiamo la comodissima funzione trace(), usata per il debug delle applicazioni. Questa funzione emette un output sulla console dell’ambiente di sviluppo Adobe Flash. Viene utilizzata principalmente nelle fasi di sviluppo e testing di “filmato”/applicativo. In XCode/Objective-C abbiamo: NSLog(). La sintassi di questa funzione è molto simile alla trace() di Actionscript:

1
NSLog( @"Sono una linea di debug" );

In Actionscript avremmo:

1
trace( "Sono una linea di debug" );

A parte l’uso della chiocciola (@), come potete vedere, sono identiche. Le differenze (e similitudini) iniziano quando si vogliano visualizzare valori di variabili; ad esempio in Actionscript potremmo avere:

1
2
3
trace( "Coordinata x:" + x + " coordinata y:" + y );
// oppure
trace( "Coordinate: ", x, y );

In Objective-C abbiamo:

1
NSLog( @"Coordinata x:%i coordinata y:%i", x, y );

Nota: NSLog() in realtà richiama la più generica funzione NSLogv() che opera sull’Apple System Log. Le funzioni sono di fatto identica, cambiano solo i parametri in ingresso.

Gli sviluppatori C troveranno molto familiare la formattazione delle stringhe, come accade per printf() o sprintf(). Per dettagli si veda String Format Specifiers.

Continua...


Stop SOPA