Верно ли, что NS64() не должен использовать производственный код?
Мне говорили это несколько раз на этом самом сайте, но я хотел убедиться, что это действительно так.
Я ожидал, что сможет посыпать вызовы функций NSLog по всему моему коду и что Xcode/gcc автоматически отключит эти вызовы при создании сборников релизов/распространения.
Не следует ли мне это использовать? Если да, то какие альтернативы наиболее распространены между опытными программистами Objective-C?
Ответы
Ответ 1
Макросы препроцессора действительно отлично подходят для отладки. Нет ничего плохого в 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
Мне было проще включить весь этот оператор в заголовок префикса, а не его собственный файл. Вы могли бы, если хотите, создать более сложную систему ведения журнала, используя DebugLog для взаимодействия с обычными объектами Objective-C. Например, у вас может быть класс ведения журнала, который записывает его в собственный файл журнала (или базу данных) и включает аргумент "приоритет", который вы можете установить во время выполнения, поэтому отладочные сообщения не отображаются в вашей версии выпуска, но сообщения об ошибках ( если вы сделали это, вы можете сделать DebugLog(), WarningLog() и т.д.).
О, и имейте в виду, что #define DEBUG_MODE
может быть повторно использован в разных местах вашего приложения. Например, в моем приложении я использую его, чтобы отключить проверки ключа лицензии и разрешить запуск приложения, если оно до определенной даты. Это позволяет мне распространять ограниченную по времени, полностью функциональную бета-версию с минимальными усилиями с моей стороны.
Ответ 2
Поместите эти 3 строки в конец файла -prefix.pch:
#ifndef DEBUG
#define NSLog(...) /* suppress NSLog when in release mode */
#endif
Вам не нужно ничего определять в своем проекте, потому что DEBUG
определяется в настройках сборки по умолчанию при создании вашего проекта.
Ответ 3
Вызовы NSLog могут быть оставлены в производственном коде, но должны присутствовать только для действительно исключительных случаев или информации, которая требуется для входа в системный журнал.
Приложения, которые засоряют системный журнал, раздражают и воспринимаются как непрофессиональные.
Ответ 4
Я не могу комментировать ответ Марка Charbonneau, поэтому я отправлю это как ответ.
В дополнение к добавлению макроса в ваш предварительно скомпилированный заголовок, вы можете использовать конфигурации сборки Target для управления определяющим (или отсутствием определения) DEBUG_MODE
.
Если вы выберете активную конфигурацию Отладка, DEBUG_MODE
будет определена, и макрос будет расширен до полного определения NSLog
.
Выбор активной конфигурации Release не будет определять DEBUG_MODE
, а ваш NSLog
ging исключен из сборки релиза.
Шаги:
- Цель > Получить информацию
- вкладка
- Найдите "Макросы препроцессора" (или
GCC_PREPROCESSOR_DEFINITIONS
)
- Выберите Конфигурация: Отладка
- Изменить определение на этом уровне
- Добавить
DEBUG_MODE=1
- Выберите Конфигурация: Отпустите
- confirm
DEBUG_MODE
не установлен в GCC_PREPROCESSOR_DEFINITIONS
если вы опустите символ '=' в определении, вы получите сообщение об ошибке из препроцессора
Кроме того, вставьте этот комментарий (показано ниже) над определением макроса, чтобы напомнить вам, откуда приходит определение DEBUG_MACRO
;)
// Target > Get Info > Build > GCC_PREPROCESSOR_DEFINITIONS
// Configuration = Release: <empty>
// = Debug: DEBUG_MODE=1
Ответ 5
ИЗМЕНИТЬ: , опубликованный Marc Charbonneau, и принес мое внимание sho намного лучше, чем этот.
Я удалил часть своего ответа, в которой предлагается использовать пустую функцию для отключения ведения журнала, когда режим отладки отключен. Часть, связанная с настройкой автоматического макропроцессора, по-прежнему актуальна, поэтому остается. Я также отредактировал имя макроса препроцессора, чтобы он лучше соответствовал ответам Марка Шарбонно.
Чтобы добиться автоматического (и ожидаемого) поведения в Xcode:
В настройках проекта перейдите на вкладку "Построение" и выберите конфигурацию "Отладка". Найдите раздел "Макросы препроцессора" и добавьте макрос с именем DEBUG_MODE
.
...
ИЗМЕНИТЬ: См. ответ Марка Charbonneau для правильного способа включения и отключения ведения журнала с помощью макроса DEBUG_MODE
.
Ответ 6
Я согласен с Мэтью. Нет ничего плохого в NSLog в производственном коде. Фактически, это может быть полезно пользователю. Тем не менее, если единственная причина, по которой вы используете NSLog, - это помочь отлаживать, то да, это должно быть удалено перед выпуском.
Кроме того, поскольку вы отметили это как вопрос iPhone, NSLog берет ресурсы, и это то, что iPhone имеет мало. Если вы NSLogging что-нибудь на iPhone, это отнимает процессорное время от вашего приложения. Используйте его с умом.
Ответ 7
Простая истина в том, что NSLog просто медленно.
Но почему? Чтобы ответить на этот вопрос, давайте узнаем, что делает NSLog, а затем как оно это делает.
Что делает NSLog точно?
NSLog делает 2 вещи:
Он записывает лог-сообщения на объект регистрации системы (asl) компании Apple. Это позволяет выводить сообщения журнала в Console.app.
Он также проверяет, идет ли поток stderr приложения к терминалу (например, когда приложение запускается через Xcode). Если это так, он записывает сообщение журнала в stderr (чтобы он отображался в консоли Xcode).
Запись в STDERR затруднительна. Это может быть выполнено с помощью fprintf и ссылки на дескриптор файла stderr. Но как насчет asl?
Лучшая документация, которую я нашел в ASL, - это 10-страничное сообщение в блоге от Peter Hosey: ссылка
Не вдаваясь в подробности, подсветка (как касается производительности) такова:
Чтобы отправить сообщение журнала в средство ASL, вы в основном открываете клиентское соединение с демоном ASL и отправляете сообщение. НО - каждый поток должен использовать отдельное клиентское соединение. Таким образом, чтобы быть потокобезопасным, каждый раз, когда вызывается NSLog, он открывает новое клиентское соединение asl, отправляет сообщение и затем закрывает соединение.
Ресурсы можно найти здесь и здесь.
Ответ 8
Как отмечено в других ответах, вы можете использовать #define для изменения использования NSLog или нет во время компиляции.
Однако более гибким способом является использование библиотеки журналов, например Cocoa Lumberjack, которая позволяет вам изменить, будет ли что-то регистрироваться во время выполнения.
В вашем коде замените NSLog на DDLogVerbose или DDLogError и т.д., добавьте #import для определений макросов и т.д. и настройте регистраторы, часто в методе applicationDidFinishLaunching.
Чтобы иметь тот же эффект, что и NSLog, код конфигурации
[DDLog addLogger:[DDASLLogger sharedInstance]];
[DDLog addLogger:[DDTTYLogger sharedInstance]];
Ответ 9
С точки зрения безопасности это зависит от того, что регистрируется. Если NSLog
(или другие регистраторы) пишет конфиденциальную информацию, вы должны удалить регистратор в производственном коде.
С точки зрения аудита аудитор не хочет смотреть на каждое использование NSLog
, чтобы гарантировать, что он не регистрирует конфиденциальную информацию. Он/она просто скажет вам удалить регистратор.
Я работаю с обеими группами. Мы проверяем код, записываем руководства по кодированию и т.д. Наш гид требует, чтобы ведение журнала отключилось в производственном коде. Поэтому внутренние команды знают, что не пытаться это сделать;)
Мы также отклоним внешнее приложение, которое регистрируется в процессе производства, потому что мы не хотим принимать риск, связанный с случайным утечкой конфиденциальной информации. Нам все равно, что говорит разработчик. Это просто не стоит времени для расследования.
И помните, мы определяем "чувствительный", а не разработчик;)
Я также воспринимаю приложение, которое выполняет много протоколирования как приложение, готовое к взлому. Там причина настолько велика, что требуется, и ее обычно не стабильность. Его прямо там с "сторожевыми" потоками, которые перезапускают висячие сервисы.
Если вы никогда не просматривали обзор архитектуры безопасности (SecArch), это те вещи, на которые мы смотрим.
Ответ 10
Вы не должны быть излишне подробными с printf или NSLog в коде выпуска. Попробуйте выполнить только printf или NSLog, если приложение имеет с ним что-то плохое, I.E. неустранимая ошибка.
Ответ 11
Имейте в виду, что NSLogs может замедлить работу интерфейса/основного потока. Лучше всего удалить их из релизов, если это абсолютно необходимо.
Ответ 12
Я бы очень рекомендовал использовать TestFlight для ведения журнала (бесплатно). Их метод переопределит NSLog (используя макрос) и позволит вам включать/выключать ведение журнала на своем сервере, журнал системы Apple и журнал STDERR для всех ваших существующих вызовов в NSLog. Приятно отметить, что вы все еще можете просматривать сообщения журнала для приложений, развернутых в тестерах и приложениях, развернутых в App Store, без журналов, отображаемых в системном журнале пользователя. Лучшее из обоих миров.