Как распечатать имя метода и номер строки и условно отключить NSLog?
Я делаю презентацию по отладке в Xcode и хотел бы получить дополнительную информацию об эффективном использовании NSLog.
в частности, у меня два вопроса:
- есть ли способ легко NSLog имя текущего метода / номер строки?
- есть ли способ" отключить " все NSLogs легко перед компиляцией для кода выпуска?
13 ответов:
вот некоторые полезные макросы вокруг NSLog я использую много:
#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__)
макрос DLog используется только для вывода, когда установлена переменная отладки (-DDEBUG в флагах C проектов для подтверждения отладки).
ALog всегда будет выводить текст (например, обычный NSLog).
вывод (например, ALog (@"Hello world")) будет выглядеть так:
-[LibraryController awakeFromNib] [Line 364] Hello world
Я
DLog
иALog
сверху, и добавилULog
которая поднимаетUIAlertView
сообщение.подведем итоги:
DLog
будет выводить какNSLog
только когда переменная отладки установленаALog
всегда будет выводить какNSLog
ULog
покажетUIAlertView
только если установлена отладочная переменная
#ifdef DEBUG # define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); #else # define DLog(...) #endif #define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); #ifdef DEBUG # define ULog(fmt, ...) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@"%s\n [Line %d] ", __PRETTY_FUNCTION__, __LINE__] message:[NSString stringWithFormat:fmt, ##__VA_ARGS__] delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil]; [alert show]; } #else # define ULog(...) #endifвот как это выглядит например:
+1 Дидерик
NSLog(@"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);
выводит имя файла, номер строки и имя функции:
/proj/cocoa/cdcli/cdcli.m 121 managedObjectContext managedObjectContext
__FUNCTION__
В C++ показывает искаженное имя__PRETTY_FUNCTION__
показывает имя функции, в какао они выглядят одинаково.Я не уверен, что это правильный способ отключения NSLog, я сделал:
#define NSLog
и никакой выход журнала не появился, однако я не знаю, есть ли у этого какие-либо побочные эффекты.
здесь одна большая коллекция констант отладки, которые мы используем. Наслаждаться.
// 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
есть новый трюк, который не дает ответа. Вы можете использовать
printf
вместоNSLog
. Это даст вам чистый журнал:С
NSLog
вы получаете такие вещи, как это:2011-11-03 13:43:55.632 myApp[3739:207] Hello Word
но с
printf
вы получаете:Hello World
используйте этот код
#ifdef DEBUG #define NSLog(FORMAT, ...) fprintf(stderr,"%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); #else #define NSLog(...) {} #endif
мой ответ этот вопрос может помочь, похоже, он похож на тот, который приготовил Дидерик. Вы также можете заменить вызов
NSLog()
со статическим экземпляром вашего собственного пользовательского класса ведения журнала, таким образом, вы можете добавить флаг приоритета для debug/warning/error messages, отправлять сообщения в файл или базу данных, а также консоль, или почти все, что вы можете придумать.#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
отключение всех NSLogs, для кого-то аллергия на макросы, вот то, что вы можете скомпилировать тоже:
void SJLog(NSString *format,...) { if(LOG) { va_list args; va_start(args,format); NSLogv(format, args); va_end(args); } }
и, используйте его почти как NSLog:
SJLog(@"bye bye NSLogs !");
из этого блога: http://whackylabs.com/rants/?p=134
чтобы дополнить ответы выше, может быть весьма полезно использовать замену для NSLog в определенных ситуациях, особенно при отладке. Например, избавление от всей информации о дате и имени/идентификаторе процесса в каждой строке может сделать вывод более читаемым и быстрым для загрузки.
следующая ссылка предоставляет довольно много полезных боеприпасов для того, чтобы сделать простой журнал намного приятнее.
легко изменить существующие NSLogs для отображения номера строки и класса, из которого они вызываются. Добавьте одну строку кода в префиксный файл:
#define NSLog(__FORMAT__, ...) NSLog((@"%s [Line %d] " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
- Это просто,например
- (void)applicationWillEnterForeground: (UIApplication *)application {
NSLog(@"%s", __PRETTY_FUNCTION__);
}
выход: - [AppDelegate applicationWillEnterForeground:]
дом на вершине выше ответы, вот что я плагиат и придумал. Также добавлена запись в память.
#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
новое дополнение к DLog. Вместо полного удаления отладки из выпущенного приложения, только отключить его. Когда пользователь имеет проблемы, которые потребовали бы отладки, просто скажите, как включить отладку в приложения и запросить данные журнала по электронной почте.
короткая версия: создайте глобальную переменную (да, ленивое и простое решение) и измените DLog следующим образом:
BOOL myDebugEnabled = FALSE; #define DLog(fmt, ...) if (myDebugEnabled) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
более длинный ответ в Jomnius iLessons iLearned:как сделать динамическую отладку входа в систему Выпущено Приложение
в течение некоторого времени я использую сайт макросов, принятых из нескольких выше. Мой фокус на входе в консоль, с акцентом на контролируемая и фильтруемая многословность; если вы не возражаете против большого количества строк журнала, но хотите легко включать и выключать их, то вы можете найти это полезным.
во-первых, я дополнительно заменяю NSLog на printf, как описано @Rodrigo выше
#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
затем я включаю вход в систему или выключено.
#ifdef DEBUG #define LOG_CATEGORY_DETAIL// comment out to turn all conditional logging off while keeping other DEBUG features #endif
в главном блоке определите различные категории соответствует модулям в вашем приложении. Также определите ведение журнала уровень выше которого не будут вызываться вызовы регистрации. Затем определите различные блюда вывода 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
таким образом, с текущими настройками для kLOGIFcategory и kLOGIFdetailLTEQ, вызов как
myLogLine(kLogVC, 2, @"%@",self);
будет печатать, но это не
myLogLine(kLogGCD, 2, @"%@",self);//GCD not being printed
ни будет
myLogLine(kLogGCD, 12, @"%@",self);//level too high
если вы хотите переопределить настройки для отдельного вызова журнала, используйте отрицательный уровень:
myLogLine(kLogGCD, -2, @"%@",self);//now printed even tho' GCD category not active.
Я нахожу несколько дополнительных символов ввода каждой строки стоят, как я могу тогда
- включите или выключите всю категорию комментариев (например, только сообщить о тех вызовах, отмеченных моделью)
- отчет о мелких деталях с номерами более высокого уровня или только самые важные вызовы, отмеченные ниже цифры
Я уверен, что многие найдут это немного излишним, но на всякий случай кто-то считает, что это соответствует их целям..