Верно ли, что 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, без журналов, отображаемых в системном журнале пользователя. Лучшее из обоих миров.