Je fais une présentation sur le débogage dans Xcode et j'aimerais obtenir plus d'informations sur l'utilisation efficace de NSLog.
En particulier, j'ai deux questions:
Voici quelques macros utiles autour de NSLog que j'utilise beaucoup:
#ifdef DEBUG
# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
# define DLog(...)
#endif
// ALog always displays output regardless of the DEBUG setting
#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
La macro DLog est utilisée pour générer uniquement lorsque la variable DEBUG est définie (-DDEBUG dans les indicateurs C du projet pour la configuration de débogage).
ALog produira toujours du texte (comme le NSLog standard).
La sortie (par exemple, ALog (@ "Hello world")) ressemblera à ceci:
-[LibraryController awakeFromNib] [Line 364] Hello world
J'ai pris DLog
et ALog
d'en haut, et j'ai ajouté ULog
, ce qui déclenche un message UIAlertView
.
Résumer:
DLog
affichera comme NSLog
uniquement lorsque la variable DEBUG est définieALog
restituera toujours comme NSLog
ULog
affichera le UIAlertView
uniquement lorsque la variable DEBUG est définie# ifdef DEBUG # définir DLog (fmt, ...) NSLog ((@ "% s [Ligne% d]" fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS __); # else # définir DLog (...) # endif # définir ALog (fmt, ...) NSLog ((@ "% s [Ligne% d] "fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS __); # ifdef DEBUG # définir ULog (fmt, ...) {UIAlertView * alert = [[UIAlertView alloc] initWithTit: [NSString stringWithFormat: @ "% s\n [Ligne% d]", __PRETTY_FUNCTION__, __LINE__] message: [NSString stringWithFormat: fmt, ## __ VA_ARGS__] delegate: nil cancelButtonTitle: @ "Ok", autre; [émission d'alerte]; } # else # définir ULog (...) # endif
Voici à quoi ça ressemble:
+1 Diederik
NSLog(@"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);
Nom du fichier de sortie, numéro de ligne et nom de la fonction:
/proj/cocoa/cdcli/cdcli.m 121 managedObjectContext managedObjectContext
__FUNCTION__
en C++ indique le nom mutilé __PRETTY_FUNCTION__
indique le nom de la fonction Nice. Dans le cacao, leur apparence est identique.
Je ne sais pas quelle est la bonne façon de désactiver NSLog, je l’ai fait:
#define NSLog
Et aucune sortie de journalisation n'est apparue, cependant je ne sais pas si cela a des effets secondaires.
Voici une grande collection de constantes de débogage que nous utilisons. Prendre plaisir.
// Uncomment the defitions to show additional info.
// #define DEBUG
// #define DEBUGWHERE_SHOWFULLINFO
// #define DEBUG_SHOWLINES
// #define DEBUG_SHOWFULLPATH
// #define DEBUG_SHOWSEPARATORS
// #define DEBUG_SHOWFULLINFO
// Definition of DEBUG functions. Only work if DEBUG is defined.
#ifdef DEBUG
#define debug_separator() NSLog( @"────────────────────────────────────────────────────────────────────────────" );
#ifdef DEBUG_SHOWSEPARATORS
#define debug_showSeparators() debug_separator();
#else
#define debug_showSeparators()
#endif
/// /// /// ////// /////
#ifdef DEBUG_SHOWFULLPATH
#define debug_whereFull() debug_showSeparators(); NSLog(@"Line:%d : %s : %s", __LINE__,__FILE__,__FUNCTION__); debug_showSeparators();
#else
#define debug_whereFull() debug_showSeparators(); NSLog(@"Line:%d : %s : %s", __LINE__,[ [ [ [NSString alloc] initWithBytes:__FILE__ length:strlen(__FILE__) encoding:NSUTF8StringEncoding] lastPathComponent] UTF8String ] ,__FUNCTION__); debug_showSeparators();
#endif
/// /// /// ////// /////
#define debugExt(args,...) debug_separator(); debug_whereFull(); NSLog( args, ##__VA_ARGS__); debug_separator();
/// /// /// ////// ///// Debug Print Macros
#ifdef DEBUG_SHOWFULLINFO
#define debug(args,...) debugExt(args, ##__VA_ARGS__);
#else
#ifdef DEBUG_SHOWLINES
#define debug(args,...) debug_showSeparators(); NSLog([ NSString stringWithFormat:@"Line:%d : %@", __LINE__, args ], ##__VA_ARGS__); debug_showSeparators();
#else
#define debug(args,...) debug_showSeparators(); NSLog(args, ##__VA_ARGS__); debug_showSeparators();
#endif
#endif
/// /// /// ////// ///// Debug Specific Types
#define debug_object( arg ) debug( @"Object: %@", arg );
#define debug_int( arg ) debug( @"integer: %i", arg );
#define debug_float( arg ) debug( @"float: %f", arg );
#define debug_rect( arg ) debug( @"CGRect ( %f, %f, %f, %f)", arg.Origin.x, arg.Origin.y, arg.size.width, arg.size.height );
#define debug_point( arg ) debug( @"CGPoint ( %f, %f )", arg.x, arg.y );
#define debug_bool( arg ) debug( @"Boolean: %@", ( arg == YES ? @"YES" : @"NO" ) );
/// /// /// ////// ///// Debug Where Macros
#ifdef DEBUGWHERE_SHOWFULLINFO
#define debug_where() debug_whereFull();
#else
#define debug_where() debug(@"%s",__FUNCTION__);
#endif
#define debug_where_separators() debug_separator(); debug_where(); debug_separator();
/// /// /// ////// /////
#else
#define debug(args,...)
#define debug_separator()
#define debug_where()
#define debug_where_separators()
#define debug_whereFull()
#define debugExt(args,...)
#define debug_object( arg )
#define debug_int( arg )
#define debug_rect( arg )
#define debug_bool( arg )
#define debug_point( arg )
#define debug_float( arg )
#endif
Il y a un nouveau truc qui ne donne pas de réponse. Vous pouvez utiliser printf
à la place de NSLog
. Cela vous donnera un journal propre:
Avec NSLog
vous obtenez des choses comme ceci:
2011-11-03 13:43:55.632 myApp[3739:207] Hello Word
Mais avec printf
vous n’obtenez que:
Hello World
Utilisez ce code
#ifdef DEBUG
#define NSLog(FORMAT, ...) fprintf(stderr,"%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#else
#define NSLog(...) {}
#endif
Ma réponse à cette question pourrait peut-être aider. Elle ressemble à celle que Diederik a préparée. Vous pouvez également vouloir remplacer l'appel à NSLog()
par une instance statique de votre propre classe de journalisation personnalisée. Vous pouvez ainsi ajouter un indicateur de priorité pour les messages de débogage/avertissement/d'erreur, ainsi que pour envoyer des messages à un fichier ou à une base de données. en tant que console, ou à peu près tout ce que vous pouvez penser.
#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
En désactivant tous les NSLogs, pour une personne allergique au MACROS, voici quelque chose que vous pouvez également compiler:
void SJLog(NSString *format,...)
{
if(LOG)
{
va_list args;
va_start(args,format);
NSLogv(format, args);
va_end(args);
}
}
Et utilisez-le presque comme NSLog:
SJLog(@"bye bye NSLogs !");
Depuis ce blog: http://whackylabs.com/rants/?p=134
Pour compléter les réponses ci-dessus, il peut être très utile d’utiliser un remplaçant pour NSLog dans certaines situations, notamment lors du débogage. Par exemple, le fait de supprimer toutes les informations de date et de nom/identifiant de processus sur chaque ligne peut rendre la sortie plus lisible et plus rapide à démarrer.
Le lien suivant fournit un peu de munitions utiles pour rendre la journalisation simple beaucoup plus agréable.
Il est facile de modifier vos NSLogs existants pour afficher le numéro de ligne et la classe à partir desquels ils sont appelés. Ajoutez une ligne de code à votre fichier de préfixe:
#define NSLog(__FORMAT__, ...) NSLog((@"%s [Line %d] " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
C'est simple, par exemple
void) applicationWillEnterForeground: (UIApplication *) application {
NSLog(@"%s", __PRETTY_FUNCTION__);
}
--- (Sortie: - [AppDelegate applicationWillEnterForeground:]
construisant au-dessus des réponses ci-dessus, voici ce que j’ai plagié et proposé. Également ajouté la journalisation de la mémoire.
#import <mach/mach.h>
#ifdef DEBUG
# define DebugLog(fmt, ...) NSLog((@"%s(%d) " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
# define DebugLog(...)
#endif
#define AlwaysLog(fmt, ...) NSLog((@"%s(%d) " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#ifdef DEBUG
# define AlertLog(fmt, ...) { \
UIAlertView *alert = [[UIAlertView alloc] \
initWithTitle : [NSString stringWithFormat:@"%s(Line: %d) ", __PRETTY_FUNCTION__, __LINE__]\
message : [NSString stringWithFormat : fmt, ##__VA_ARGS__]\
delegate : nil\
cancelButtonTitle : @"Ok"\
otherButtonTitles : nil];\
[alert show];\
}
#else
# define AlertLog(...)
#endif
#ifdef DEBUG
# define DPFLog NSLog(@"%s(%d)", __PRETTY_FUNCTION__, __LINE__);//Debug Pretty Function Log
#else
# define DPFLog
#endif
#ifdef DEBUG
# define MemoryLog {\
struct task_basic_info info;\
mach_msg_type_number_t size = sizeof(info);\
kern_return_t e = task_info(mach_task_self(),\
TASK_BASIC_INFO,\
(task_info_t)&info,\
&size);\
if(KERN_SUCCESS == e) {\
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; \
[formatter setNumberStyle:NSNumberFormatterDecimalStyle]; \
DebugLog(@"%@ bytes", [formatter stringFromNumber:[NSNumber numberWithInteger:info.resident_size]]);\
} else {\
DebugLog(@"Error with task_info(): %s", mach_error_string(e));\
}\
}
#else
# define MemoryLog
#endif
Nouvelle addition à DLog. Au lieu de supprimer totalement le débogage de l'application publiée, ne le désactivez que. Lorsque l'utilisateur a des problèmes nécessitant un débogage, indiquez simplement comment activer le débogage dans les applications publiées et demander les données du journal par courrier électronique.
Version courte: créez une variable globale (oui, solution simple et lente) et modifiez DLog comme ceci:
BOOL myDebugEnabled = FALSE;
#define DLog(fmt, ...) if (myDebugEnabled) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
Réponse plus longue chez Jomnius iLessons iLearned: Procédure de journalisation de débogage dynamique dans une application publiée
Depuis quelque temps, j'utilise un site de macros adoptées par plusieurs d'entre elles. Je me concentre sur la journalisation dans la console, en mettant l’accent sur verbosité contrôlée et filtrée; Si cela ne vous dérange pas beaucoup de lignes de journal, mais que vous voulez facilement activer/désactiver des lots, alors cela peut vous être utile.
Tout d'abord, je remplace éventuellement NSLog avec printf comme décrit par @Rodrigo ci-dessus
#define NSLOG_DROPCHAFF//comment out to get usual date/time ,etc:2011-11-03 13:43:55.632 myApp[3739:207] Hello Word
#ifdef NSLOG_DROPCHAFF
#define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#endif
Ensuite, j'activer ou désactiver la connexion.
#ifdef DEBUG
#define LOG_CATEGORY_DETAIL// comment out to turn all conditional logging off while keeping other DEBUG features
#endif
Dans le bloc principal, définissez divers catégories correspondant aux modules de votre application. Définissez également une journalisation nivea au-dessus de laquelle les appels de journalisation ne seront pas appelés. Puis définissez divers variantes de la sortie NSLog
#ifdef LOG_CATEGORY_DETAIL
//define the categories using bitwise leftshift operators
#define kLogGCD (1<<0)
#define kLogCoreCreate (1<<1)
#define kLogModel (1<<2)
#define kLogVC (1<<3)
#define kLogFile (1<<4)
//etc
//add the categories that should be logged...
#define kLOGIFcategory kLogModel+kLogVC+kLogCoreCreate
//...and the maximum detailLevel to report (use -1 to override the category switch)
#define kLOGIFdetailLTEQ 4
// output looks like this:"-[AppDelegate myMethod] log string..."
# define myLog(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%s " format), __PRETTY_FUNCTION__, ##__VA_ARGS__);}
// output also shows line number:"-[AppDelegate myMethod][l17] log string..."
# define myLogLine(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%s[l%i] " format), __PRETTY_FUNCTION__,__LINE__ ,##__VA_ARGS__);}
// output very simple:" log string..."
# define myLogSimple(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"" format), ##__VA_ARGS__);}
//as myLog but only shows method name: "myMethod: log string..."
// (Doesn't work in C-functions)
# define myLog_cmd(category,detailLevel,format,...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%@: " format), NSStringFromSelector(_cmd), ##__VA_ARGS__);}
//as myLogLine but only shows method name: "myMethod>l17: log string..."
# define myLog_cmdLine(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%@>l%i: " format), NSStringFromSelector(_cmd),__LINE__ , ##__VA_ARGS__);}
//or define your own...
// # define myLogEAGLcontext(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%s>l%i (ctx:%@)" format), __PRETTY_FUNCTION__,__LINE__ ,[EAGLContext currentContext], ##__VA_ARGS__);}
#else
# define myLog_cmd(...)
# define myLog_cmdLine(...)
# define myLog(...)
# define myLogLine(...)
# define myLogSimple(...)
//# define myLogEAGLcontext(...)
#endif
Ainsi, avec les paramètres actuels de kLOGIFcategory et kLOGIFdetailLTEQ, un appel comme
myLogLine(kLogVC, 2, @"%@",self);
imprimera mais cela ne sera pas
myLogLine(kLogGCD, 2, @"%@",self);//GCD not being printed
ni sera
myLogLine(kLogGCD, 12, @"%@",self);//level too high
Si vous souhaitez remplacer les paramètres d'un appel de journal individuel, utilisez un niveau négatif:
myLogLine(kLogGCD, -2, @"%@",self);//now printed even tho' GCD category not active.
Je trouve que les quelques caractères supplémentaires de frappe de chaque ligne valent la peine, alors je peux
Je suis sûr que beaucoup trouveront cela un peu exagéré, mais juste au cas où quelqu'un trouve que cela convient à leurs objectifs.