Чи потрібно відключити NSLog перед випуском програми?


117

Якщо випустити додаток для iPhone, якщо я відключу, чи NSLog();буде він краще працювати?


1
У своєму поточному проекті я використовую UALogger . Він не входить у виробництво , якщо ви не запитаєте це прямо. І має інші переваги перед простими NSLog, такими як рівень тяжкості (з DEBUG , INFO та ін.) Поза межами коробки. Хороша робота!
Антон Гаєнко

1
Щоб відповісти на ваше запитання про те, "чи буде це краще?" Так, це так, але прибутковість, яку ви отримуєте, залежить від того, скільки у NSLog()вас є програми. NSLog()потрібен час для виконання та додає додаткові накладні витрати на час роботи вашого додатка. У будь-якому випадку, якщо це допомагає у виконанні простого макроса препроцесора DEBUG, тоді нам слід його відключити.
Скотт

Я б також запропонував, якщо у вашому коді багато заяв NSLog / print, це може запропонувати вам трохи часу вивчити налагоджувач. Я регулярно встановлюю точки перерви, які друкують інформацію, яка мене цікавить, і автоматично продовжую. Так, це може трохи уповільнити біг вниз, але в більшості випадків це не переважає. Також умовні перерви, щоб ви могли розслідувати, коли сталося щось несподіване.
bshirley

Відповіді:


127

Один із способів зробити це - зайти в налаштування Build і під конфігурацією налагодження додати значення до значення "Препроцесорні макроси", наприклад:

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
Я не приймаю вихід, оскільки це позбавляє вас можливості отримувати кращі звіти про помилки від користувачів. використовуйте журнал async і logLevels, щоб обмежити показник продуктивності майже до нуля! (див. какао-дрова або java's log4j
Daij-Djan

2
Я б пішов з #if, а не #ifdef, оскільки DEBUG_MODE 0 все одно пройде справжній шлях
Граді Гравець

1
це не відповідає на питання
Мартін Млостек

117

Оновлення для Xcode 5 та iOS 7

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

Так, ви повинні видалити будь-яку заяву NSLog з коду випуску, оскільки це просто уповільнює ваш код і не має користі у версії випуску. На щастя, в Xcode 5 (iOS 7) надзвичайно просто видалити всі ваші заяви NSLog "автоматично" у версії версій. То чому б цього не зробити.

Спочатку 3 кроки, які потрібно зробити, потім деякі пояснення

1) у вашому проекті Xcode знайдіть файл "yourProjectName-prefix.pch" (зазвичай ви знайдете це у групі "підтримуючі файли", де знаходиться ваш файл main.m

2) додайте ці 3 рядки в кінці файлу '.pch':

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

3) перевірити різницю між вашою версією "налагодження" та "випуском". Один із способів зробити це - "редагувати схему" -> "запустити ім'я програми" -> у вкладці "інформація" вибрати за допомогою випадаючого поля між налагодженням та випуском. У версії випуску ви не побачите жодного виходу NSLog на консолі налагодження!

Як це все працює?

Перш за все, потрібно знати, що препроцесор є відносно «німим», і він просто виконує функцію «заміни тексту» перед тим, як викликати компілятор. Він замінює все, що ви "#define", тим, що слідує за #defineтвердженням.

#define NSLog(...);

(...)Чи означає «нічого» між дужками (). Зверніть увагу і ;на кінець. Це не обов'язково, оскільки компілятор оптимізує це, але мені подобається розміщувати його там, оскільки це "правильніше". Після нашого #defineнемає "нічого", тому препроцесор замінить його на "нічого", і він просто викине повну лінію, починаючи з NSLog...і включаючи ;.

визначити заяви можна зробити умовними, використовуючи #ifdef(якщо визначено) або #ifndef(якщо не визначено)

тут ми пишемо #ifndef DEBUG, що означає "якщо символ DEBUG не визначений". #ifdefАбо #ifndefпотреба бути «закритим» з#endif

Xcode 5 визначає за замовчуванням символ "DEBUG" для нас, коли в режимі de build є "DEBUG". У "релізі" це не визначено. ви можете перевірити це в налаштуваннях свого проекту, на вкладці "Налаштування параметрів" -> прокрутіть униз до розділу "Apple LLVM 5.0 - Попередня обробка" -> макроси препроцесора. Ви побачите, що символ "DEBUG" не визначений для версій версій!

нарешті, .pch файл створюється Xcode автоматично та автоматично включається у кожен вихідний файл під час компіляції. Так що, ніби ви все це помістили #defineу кожен свій вихідний файл.


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

1
Якщо це старіший проект, який не має прапора налагодження в макросах препроцесора, важливо додати "налагодження = 1" для проекту, а не ціль
Priebe

1
Крім того, не використовуйте NSLogяк заяву нічого не робити, наприклад, if(AllCool) NSLog(@"Cool!Do Nothing!"); else...замість цього NSLogif(AllCool) {NSLog(@"Cool!Do Nothing!");} else...
впишіть

33

Майже всі вище відповіді пропонують рішення, але не пояснюють проблему. Я здійснив пошук в Google, і знайшов причину. Ось моя відповідь:

Так, якщо ви прокоментуєте NSLog у своїй версії випуску, продуктивність стане кращою. Тому що NSLog досить повільний. Чому? NSLog зробить дві речі: 1) записувати повідомлення в журнал Apple System Logging (ASL), 2), якщо програма працює в xcode, вона також пише в stderr.

Основна проблема полягає в першій. Щоб досягти безпеки потоку, кожен раз, коли викликається NSLog, він відкриває з'єднання з об'єктом ASL , відправляє повідомлення та закриває з'єднання. Операція підключення дуже дорога. Ще одна причина полягає в тому, що NSLog витрачає певний час, щоб отримати часову позначку для входу.

Посилальна з тут .


23

Мій особистий фаворит - використовувати різноманітний макрос.

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

1
Куди ти це поклав?
користувач6631314

20

На додачу до всіх людей, які з розумом прокоментували, що взагалі не викликати NSLog()виробництво працює трохи швидше, додам:

Усі ці NSLog()вихідні рядки видно всім, хто завантажує вашу програму з магазину та запускає її із пристроєм, підключеним до Mac, що працює з Xcode (через вікно Організатора).

Залежно від інформації, яку ви реєструєте (особливо, якщо ваш додаток контактує із сервером, робить аутентифікацію тощо), це може бути серйозною проблемою безпеки .


спасибі за інформацію - це десь у документі чи просто що ви самі виявили? Чи все-таки це правда для друку в Swift?
Ронні Веберс

Я не пам’ятаю читання жодної документації. Я щойно встановив на своєму пристрої свою архівовану збірку (той самий двійковий файл, який я подав у магазин) і підключив її до Xcode. Я поняття не маю, чи те саме для Свіфта print(), але, швидше за все, так і є.
Nicolas Miari

@NicolasMiari Що ви маєте на увазі під підключенням до Xcode? Як ми можемо підключити наш двійковий код до Xcode, насправді я хочу спробувати те саме. Тому, будь ласка, підкажіть. Дякую.
iDevAmit

@iDeveloper Я маю на увазі завантаження програми з AppStore на пристрій (наприклад, iPhone), підключіть цей пристрій до Xcode через USB, запустіть додаток і перегляньте журнали у вікні «Пристрої» Xcode.
Ніколас Міарі

3
@Whasssaaahhh друк не виводиться на консолі пристрою. Я щойно перевірив це
Anish Parajuli 웃

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 per .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 все ще викликається, а його аргументи
розбираються

0
var showDebugLogs = false;

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

Це також сприймає додаткові аргументи. Просто значення параметра showDebugLogs до істинного чи помилкового, відповідно до вашої потреби


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