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


117

При выпуске приложения для iPhone, если я отключу NSLog();его, оно будет работать лучше?


1
В моем текущем проекте я использую UALogger . Он не входит в производство , если вы не спрашиваете об этом явно. И имеет другие преимущества по сравнению с обычным NSLog, такие как уровни серьезности (с DEBUG , INFO и т. Д.) Из коробки. Хорошая работа!
Антон Гаенко

1
Чтобы ответить на ваш вопрос "будет ли он работать лучше?" Да, это так, но получаемая вами доходность зависит от того, сколько у NSLog()вас их в приложении. NSLog()требует времени для выполнения и добавляет дополнительные накладные расходы во время выполнения вашего приложения. В любом случае, если это помогает в производительности с помощью простого макроса препроцессора DEBUG, мы должны отключить его.
Скотт

Я также предлагаю, если в вашем коде много операторов NSLog / print, это может предложить вам потратить некоторое время на изучение отладчика. Я регулярно устанавливаю точки останова, которые выводят на печать интересующую меня информацию и автоматически продолжаю. Да, это может немного замедлить работу, но в большинстве случаев это не слишком сильно. Кроме того, условные перерывы, чтобы вы могли расследовать, когда произошло что-то неожиданное.
bshirley

Ответы:


127

Один из способов сделать это - зайти в настройки сборки и в разделе «Отладка» добавить значение «Макросы препроцессора», например:

DEBUG_MODE=1

Убедитесь, что вы делаете это только для конфигурации отладки, а не для версий Beta или Release. Затем в общем файле заголовка вы можете сделать что-то вроде:

#ifdef DEBUG_MODE
#define DLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define DLog( s, ... ) 
#endif

Теперь вместо NSLog использования DLogвезде. При тестировании и отладке вы получите отладочные сообщения. Когда вы готовы выпустить бета-версию или финальную версию, все эти DLogстроки автоматически становятся пустыми и ничего не выводится. Таким образом, не NSLogsтребуется ручная установка переменных или их комментирование . Выбор цели сборки позаботится об этом.


В Xcode 4.5 он выдает предупреждение, в котором говорится: «Неявное объявление функции DLog недопустимо в C99», поэтому эта вещь не работает.
Сергей Грищев

2
@SergiusGee: вы получаете предупреждение о неявном объявлении, если объявление для функции не может быть найдено, и в этом случае он думает, что вы пытаетесь его объявить. Убедитесь, что ваш класс имеет доступ к файлу заголовка, в котором он объявлен.
sudo rm -rf

1
Id не запрещает выход из системы, поскольку это лишает вас возможности получать более качественные отчеты об ошибках от пользователей. используйте асинхронное ведение журнала и logLevels, чтобы ограничить снижение производительности почти до нуля! (см. cocoa
lumberjack

2
Я бы выбрал #if, а не #ifdef, так как DEBUG_MODE 0 по-прежнему будет проходить истинный путь
Grady Player

1
это не отвечает на вопрос
Мартин Млостек

117

Обновление для Xcode 5 и iOS 7

примечание: для решения Xcode 7 / Swift 2.1 для удаления операторов print () в сборке выпуска найдите мой ответ здесь .

Да, вам следует удалить любой оператор NSLog в коде выпуска, так как он просто замедляет ваш код и не используется в выпускной версии. К счастью, в Xcode 5 (iOS 7) удивительно просто удалить все ваши операторы NSLog «автоматически» в сборках выпуска. Так почему бы не сделать это.

Сначала три шага, которые нужно предпринять, затем объяснение

1) в вашем проекте Xcode найдите файл yourProjectName-prefix.pch (обычно вы найдете его в группе «вспомогательные файлы», где находится ваш файл main.m

2) добавьте эти 3 строки в конец файла .pch:

#ifndef DEBUG
   #define NSLog(...);
#endif

3) проверьте разницу между вашей «отладочной» и «выпускной» версией. Один из способов сделать это - «изменить схему» -> «запустить имя приложения» -> на вкладке «информация» выбрать в раскрывающемся списке между отладкой и выпуском. В выпускной версии вы не увидите вывода NSLog в консоли отладки!

Как это все работает?

Прежде всего, нужно знать, что препроцессор относительно «тупой» и просто действует как «заменитель текста» перед вызовом компилятора. Он заменяет все, что вы '#define', тем, что следует за #defineоператором.

#define NSLog(...);

(...)Означает «ничего» между скобками (). Помните также ;о конце. Это не является строго необходимым, поскольку компилятор оптимизирует это, но мне нравится помещать это там, поскольку это более «правильно». После нашего #defineидет «ничего», поэтому препроцессор заменит его на «ничего», и поэтому он просто выбросит всю строку, начиная с NSLog...до и включая; .

Операторы define могут быть условными с помощью #ifdef(если определено) или#ifndef (если не определено)

здесь мы пишем #ifndef DEBUG, что означает «если символ DEBUG не определен». #ifdefили#ifndef потребность быть «закрытым» с#endif

Xcode 5 по умолчанию определяет для нас символ «DEBUG», когда режим сборки - «DEBUG». В «выпуске» это не определено. вы можете проверить это в настройках вашего проекта, на вкладке «Параметры сборки» -> прокрутите вниз до раздела «Apple LLVM 5.0 - Предварительная обработка» -> макросы препроцессора. Вы увидите, что символ «DEBUG» не определен для сборок выпуска!

наконец, файл .pch создается Xcode автоматически и автоматически включается в каждый исходный файл во время компиляции. Это как если бы вы поместили все #defineэто в каждый из ваших исходных файлов.


1
Спасибо @Whasssaaahhh, отлично работает. Будьте осторожны, чтобы не помещать код в операторы журнала! Препроцессор удалит все NSLogоператоры, не обращая внимания на то, что находится внутри.
Эрик Платон,

1
Если это более старый проект, у которого нет флага отладки в макросах препроцессора, важно добавить «debug = 1» для проекта, а не для цели
Прибе

1
Кроме того, не используйте NSLogвыражение «ничего не делать», например, if(AllCool) NSLog(@"Cool!Do Nothing!"); else...вместо этого NSLogif(AllCool) {NSLog(@"Cool!Do Nothing!");} else...
вставьте

33

Почти все приведенные выше ответы предлагают решение, но не объясняют проблему. Я поискал в гугле и нашел причину. Вот мой ответ:

Да, если вы закомментируете NSLog в своей релизной версии, производительность станет лучше. Потому что NSLog довольно медленный. Зачем? NSLog будет делать две вещи: 1) записывать сообщения журнала в системный журнал Apple (ASL), 2) если приложение работает в xcode, оно также записывает в stderr.

Основная проблема заключается в первом. Чтобы обеспечить потокобезопасность, каждый раз , когда вызывается NSLog, он открывает соединение с функцией ASL , отправляет сообщение и закрывает соединение. Операция подключения очень дорогая. Другая причина заключается в том, что NSLog тратит некоторое время на получение отметки времени для регистрации.

Ссылка отсюда .


23

Лично я предпочитаю использовать макрос с переменными числами.

#ifdef NDEBUG
    #define NSLog(...) /* suppress NSLog when in release mode */
#endif

1
Куда вы это положили?
user6631314

20

В дополнение ко всем людям, которые мудро прокомментировали, что отсутствие звонков NSLog()в продакшн работает немного быстрее, я добавлю следующее:

Все эти NSLog()выходные строки видны всем, кто загружает ваше приложение из магазина и запускает его с устройством, подключенным к Mac, на котором запущен Xcode. (через окно Организатора).

В зависимости от того, какую информацию вы регистрируете (и особенно если ваше приложение связывается с сервером, выполняет аутентификацию и т. Д.), Это может быть серьезной проблемой безопасности .


спасибо за информацию - это где-то в документации, или вы сами это обнаружили? Это все еще верно для печати в Swift?
Ронни Веберс

Я не помню, чтобы читал документацию. Я только что установил свою заархивированную сборку (тот же двоичный файл, который я отправил в магазин) на свое устройство и подключил его к Xcode. Понятия не имею, то же самое для Swift print(), но, скорее всего, это так.
Николас Миари

@NicolasMiari Что вы имеете в виду, говоря о подключении к Xcode? Как мы можем подключить наш двоичный код к Xcode, я хочу попробовать то же самое. Пожалуйста, предложите. Спасибо.
iDevAmit

@iDeveloper Я имею в виду загрузите ваше приложение из AppStore на устройство (например, iPhone), подключите это устройство к Xcode через USB, запустите приложение и посмотрите журналы в окне Xcode «Устройства».
Николас Миари

3
@Whasssaaahhh печать не выводится в консоль устройства .. Я только что проверил это
Аниш Параджули 웃

13

Настройка проекта по умолчанию

Внутри текущей настройки проекта по умолчанию в Xcode NS_BLOCK_ASSERTIONSмакрос будет установлен в 1 в версии выпуска и DEBUG=1в версии отладки.

Итак, я предпочитаю следующий метод.

// NS_BLOCK_ASSERTIONS is defined by default, as shown in the screenshot above.
// Or, you can define yourself Flags in the `Other C Flags` -> `Release`.
#ifndef NS_BLOCK_ASSERTIONS
    #define _DEBUG
#endif

#ifdef _DEBUG
// for debug mode 
#define DLog(fmt,...) NSLog(@"%s " fmt, __FUNCTION, ##__VA_ARGS__) 
... /// something extra
#else
// for release mode
#define DLog(fmt,...) /* throw it away */
... /// something extra
#endif

5

Да, вы должны отключить его. Особенно, если вы пытаетесь максимизировать скорость своего кода. NSLogging вещей слева и справа загрязняет системный журнал, который другие разработчики могут пытаться раскопать, и может иметь большое влияние на критичный по скорости код (внутренние циклы и т. Д.) Я случайно оставил некоторые сообщения журнала в рекурсивной функции один раз и должен выпустить обновление с «увеличением скорости на 30%!» несколько недель спустя ... ;-)


5

Все хорошие ответы, однако вот еще один небольшой трюк, который вы можете использовать, в основном, на этапах разработки / тестирования вашего приложения.

Это также может быть полезно для кода выпуска приложения, если вы хотите отключить только ВАШ код отладки, а не сообщения, которые могут указывать на проблемы, находящиеся вне прямого контроля вашего кода.

Хитрость:

Вы можете отключить NSLog для файла .m, просто включив следующую строку в верхней части файла .m :

#define NSLog(...)

( ПРИМЕЧАНИЕ: НЕ помещайте это файл .h, только файл .m! )

Это просто заставляет компилятор вычислять NSLog(), вместо этого расширяя ваш макрос препроцессора. Макрос ничего не делает, только удаляет аргументы.

если вы хотите снова включить его, вы всегда можете использовать

#undef NSLog

Вы можете, например, просто предотвратить вызовы NSLog вокруг определенной группы методов, выполнив что-то вроде

#define NSLog(...)
-(void) myProblematicMethodThatSometimesNeedsDebugging {
    ...
}
#undef NSLog

3

NSLog работает медленно и не должен использоваться для сборок выпуска. Простой макрос, подобный приведенному ниже, отключит его вместе со всеми возможными утверждениями, которые также следует отключить. В менее распространенном случае, когда вам нужен NSLog в сборке выпуска, просто вызовите его напрямую. Не забудьте добавить «-DNDEBUG» в настройки сборки «другие флаги c».

#ifdef NDEBUG
#define MYLog(f, ...) 
#else
#define MYLog(f, ...) NSLog(f, ## __VA_ARGS__)
#endif


0

как насчет этого?

#ifndef DEBUG_MODE
        fclose(stderr);     // the simplest way to disable output from NSLog
#endif    

1
это отключает вывод, но не экономит время обработки, т.е. NSLog по-прежнему вызывается и его аргументы анализируются
dwery

0
var showDebugLogs = false;

    func DLog(format: String, args: CVarArgType...) {
        if showDebugLogs{
        println(String(format: format, arguments: args))
        }
    }

Это также примет дополнительные аргументы. Просто установите для параметра showDebugLogs значение true или false, в зависимости от ваших потребностей.


Это хорошо, но по-прежнему имеет проблему накладных расходов на вызовы и любых накладных расходов (и потенциальных побочных эффектов) при вычислении любых аргументов, переданных Dlogфункции.
Тодд Леман
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.