В этом кратком совете мы узнаем, как настроить вывод, генерируемый NSLog, для более эффективной отладки программ. Читай дальше!
проблема
По умолчанию NSLog отображает вывод в следующем формате:
1
|
Date Time OurApp[<processid>] NSLog output
|
Пример из реальной жизни может выглядеть так:
1
|
20130803 00:35:53.038 TestApp[460:c07] Value of result = 20
|
Вывод по умолчанию хорош, но оставляет желать лучшего. В большинстве случаев мы хотим видеть следующее в операторе журнала:
- Имя исходного файла, где был вызван NSLog ()
- Номер строки исходного кода, где был вызван NSLog ()
- Имя класса и метода, где был вызван NSLog ()
- Скрыть метку времени, имя приложения и информацию об идентификаторе процесса
- Включить / отключить информацию журнала путем изменения режима (например, отладка, выпуск, подготовка)
Короче говоря, мы бы хотели, чтобы NSLog был таким:
1
|
(ClassName MethodName) (SourceFileName:LineNumber) NSLog output
|
Решение
Давайте сначала посмотрим, как работает NSLog без изменений. NSLog — это просто функция C, встроенная в базовый каркас Cocoa, и она ведет себя так же, как любая другая переменная функция C. В частности, NSLog отправляет сообщения об ошибках в средство Apple System Log. Он делает это просто, передавая свои аргументы функции NSLogv .
Поскольку NSLog — это просто оболочка для NSLogv, мы можем переопределить NSLog с помощью нашего собственного пользовательского вызова NSLogv. Это именно то, что я покажу вам, как это сделать в этом уроке.
1. Начните новый проект
Создайте новый проект iOS в Xcode с шаблоном Empty Application . Назовите это ExtendNSLog . Установите флажок «Автоматический подсчет ссылок», но снимите флажки «Основные данные» и «Юнит тесты».
2. Создайте класс Objective-C
Теперь создайте заголовочный файл вместе с проектом. Выберите « Новый файл»> «Класс Objective-C» . Установите имя класса в ExtendNSLogFunctionality. который будет подклассом NSObject.
3. Добавьте пользовательскую логику NSLog
Шаг 1
Откройте ExtendNSLogFunctionality.h и поместите следующий код в заголовок:
1
2
3
4
5
6
7
8
9
|
#import <Foundation/Foundation.h>
#ifdef DEBUG
#define NSLog(args…) ExtendNSLog(__FILE__,__LINE__,__PRETTY_FUNCTION__,args);
#else
#define NSLog(x…)
#endif
void ExtendNSLog(const char *file, int lineNumber, const char *functionName, NSString *format, …);
|
Приведенное выше условие будет определять оператор NSLog
только когда определено DEBUG. Когда DEBUG не определен, оператор NSLog ничего не сделает. Возникает вопрос: как вы управляете, когда определяется DEBUG? Это можно сделать, назначив DEBUG = 1 в настройках препроцессора для вашего проекта.
Для этого щелкните цель приложения и выберите вкладку «Настройки сборки». Далее убедитесь, что выбраны опции «Все» и «Комбинированные». Выполните поиск «предварительной обработки» и найдите раздел «Макросы препроцессора». Затем просто добавьте «DEBUG = 1» в раздел «Отладка».
Обратите внимание, что в более поздних шаблонах проектов Xcode уже будет макрос DEBUG = 1, определенный для конфигурации сборки Debug в разделе Макросы препроцессора. Для получения дополнительной информации обратитесь к этому сообщению на StackOverflow .
Шаг 2
С заданным макросом отладки наша следующая задача — написать собственную версию NSLog. Откройте ExtendNSLogFunctionality.m и добавьте следующий код:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#import «ExtendNSLogFunctionality.h»
void ExtendNSLog(const char *file, int lineNumber, const char *functionName, NSString *format, …)
{
// Type to hold information about variable arguments.
va_list ap;
// Initialize a variable argument list.
va_start (ap, format);
// NSLog only adds a newline to the end of the NSLog format if
// one is not already there.
// Here we are utilizing this feature of NSLog()
if (![format hasSuffix: @»\n»])
{
format = [format stringByAppendingString: @»\n»];
}
NSString *body = [[NSString alloc] initWithFormat:format arguments:ap];
// End using variable argument list.
va_end (ap);
NSString *fileName = [[NSString stringWithUTF8String:file] lastPathComponent];
fprintf(stderr, «(%s) (%s:%d) %s»,
functionName, [fileName UTF8String],
lineNumber, [body UTF8String]);
}
|
Шаг 3
Теперь добавьте файл ExtendNSLogFunctionality.h в заголовочный файл префикса Prefix.pch в разделе #ifdef __OBJC__.
1
2
3
4
5
|
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import «ExtendNSLogFunctionality.h»
#endif
|
Чтобы лучше понять заголовки префиксов, взгляните на эту запись в Википедии . Относительно лучших практик заголовка префикса, прочитайте этот пост StackOverflow .
4. Пример пользовательского журнала
Теперь добавьте NSLog в любом месте вашего кода проекта. В моем случае я решил добавить один в метод AppDelegate.m -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
.
1
2
|
int result = 20;
NSLog(@»Value of result : %d», result);
|
Если вы соберете и запустите проект с конфигурацией Debug сейчас, вы должны увидеть что-то вроде этого:
1
|
([AppDelegate application:didFinishLaunchingWithOptions:]) (AppDelegate.m:21) Value of result : 20
|
Ура! Этот вывод гораздо полезнее, чем реализация по умолчанию. Надеюсь, вы обнаружите, что эта техника сэкономит вам много времени при отладке ваших собственных программ!