Как распечатать имя метода и номер строки и условно отключить NSLog?

Я делаю презентацию по отладке в Xcode и хотел бы получить более подробную информацию об использовании NSLog эффективно.

В частности, у меня есть два вопроса:

  • Есть ли способ легко NSLog текущего имени метода/номера строки?
  • Есть ли способ "отключить" все NSLogs перед компиляцией для кода выпуска?

Ответ 1

Вот несколько полезных макросов вокруг 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 используется для вывода только при установке переменной DEBUG (-DDEBUG в флагах проекта C для проверки отладки).

ALog всегда выводит текст (например, обычный NSLog).

Выход (например, ALog (@ "Hello world" )) будет выглядеть так:

-[LibraryController awakeFromNib] [Line 364] Hello world

Ответ 2

Я взял DLog и ALog сверху и добавил ULog, который вызывает сообщение UIAlertView.

Подводя итог:

  • DLog будет выводиться как NSLog только при установке переменной DEBUG
  • ALog всегда будет выводиться как NSLog
  • ULog покажет UIAlertView только при установке переменной DEBUG
#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

Это выглядит так:

Debug UIAlertView

+1 Дидерик

Ответ 3

NSLog(@"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);

Выводит имя файла, номер строки и имя функции:

/proj/cocoa/cdcli/cdcli.m 121 managedObjectContext managedObjectContext

__FUNCTION__ в С++ показывает искаженное имя __PRETTY_FUNCTION__ показывает хорошее имя функции, в cocoa они выглядят одинаково.

Я не уверен, что является правильным способом отключения NSLog, я сделал:

#define NSLog

И никаких результатов регистрации не появилось, однако я не знаю, есть ли у этого побочные эффекты.

Ответ 4

Вот одна большая коллекция констант отладки, которые мы используем. Наслаждайтесь.

// 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

Ответ 5

Есть новый трюк, который не дает ответа. Вы можете использовать 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

Ответ 6

Мой ответ на этот вопрос может помочь, похоже, что он похож на тот, который приготовил Diederik. Вы также можете заменить вызов на NSLog() статическим экземпляром собственного пользовательского класса ведения журнала, таким образом вы можете добавить флаг приоритета для сообщений об отладке/предупреждении/ошибке, отправлять сообщения в файл или базу данных, а также консоль или почти все, что вы можете придумать.

#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

Ответ 7

Отключение всех NSLogs, для кого-то, страдающего аллергией на MACROS, вот что вы можете скомпилировать:

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

Ответ 8

В дополнение к приведенным выше ответам, может быть весьма полезно использовать замену для NSLog в определенных ситуациях, особенно при отладке. Например, избавление от всей информации о имени и имени даты и процесса в каждой строке может сделать вывод более читабельным и более быстрым для загрузки.

Следующая ссылка содержит довольно много полезных патронов для упрощения записи.

http://cocoaheads.byu.edu/wiki/a-different-nslog

Ответ 9

Легко изменить существующие NSLogs, чтобы отобразить номер строки и класс, из которых они вызывается. Добавьте в файл префикса одну строку кода:

#define NSLog(__FORMAT__, ...) NSLog((@"%s [Line %d] " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)

Ответ 10

построение сверху ответов сверху, вот что я плагиатом и придумал. Также добавлена ​​запись в память.

#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

Ответ 11

Это просто, для примера

- (void) applicationWillEnterForeground: (приложение UIApplication *) {

    NSLog(@"%s", __PRETTY_FUNCTION__);

}

Вывод: - [AppDelegate applicationWillEnterForeground:]

Ответ 12

Новое дополнение к DLog. Вместо полного удаления отладки из выпущенного приложения отключите его. Когда у пользователя возникают проблемы, требующие отладки, просто расскажите, как включить отладку в выпущенном приложении и запросить данные журнала по электронной почте.

Краткая версия: создайте глобальную переменную (да, ленивое и простое решение) и измените DLog следующим образом:

BOOL myDebugEnabled = FALSE;
#define DLog(fmt, ...) if (myDebugEnabled) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);

Более длинный ответ в Jomnius iLessons iLearned: Как вести динамический отладочный журнал в выпущенном приложении

Ответ 13

В течение некоторого времени я использовал сайт макросов, принятый из нескольких выше. Mine фокусируется на регистрации в Консоли с акцентом на контролируемую и фильтрованную многословие; если вы не возражаете против множества строк журнала, но хотите легко переключаться между ними, вы можете найти это полезным.

Во-первых, я необязательно заменяю 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.

Я нахожу, что несколько лишних символов ввода каждой строки стоят того, что я могу сделать

  • Включить или выключить полную категорию комментариев (например, только сообщать о тех вызовах, которые отмечены как "Модель" ).
  • отчет о мелких деталях с номерами более высокого уровня или только самые важные вызовы, отмеченные более низкими номерами

Я уверен, что многие посчитают это немного излишним, но на всякий случай кто-то найдет, что это соответствует их целям.