Czy muszę wyłączyć NSLog przed wydaniem aplikacji?

117

Kiedy wypuszczam aplikację na iPhone'a, czy jeśli ją wyłączę, NSLog();będzie działać lepiej?

RAGOpoR
źródło
1
W moim obecnym projekcie używam UALoggera . Nie loguje się do produkcji , jeśli nie poprosisz o to wyraźnie. I ma inne zalety w stosunku do zwykłego NSLog, takie jak poziomy ważności (z DEBUG , INFO itp.) Po wyjęciu z pudełka. Dobra robota!
Anton Gaenko,
1
Odpowiadając na pytanie „czy będzie działać lepiej?” Tak, ale uzyskany zysk zależy od tego, ile NSLog()masz w swojej aplikacji. NSLog()wymaga czasu na wykonanie i dodaje dodatkowe obciążenie do środowiska uruchomieniowego aplikacji. W każdym razie, jeśli pomaga to w działaniu z prostym makrem preprocesora DEBUG, to powinniśmy je wyłączyć.
Scott,
Sugerowałbym również, że jeśli masz dużo instrukcji NSLog / print w swoim kodzie, może to zasugerować, że powinieneś poświęcić trochę czasu na poznanie debuggera. Regularnie ustawiam punkty przerwania, które drukują informacje, które mnie interesują, i automatycznie kontynuuję. Tak, może trochę spowolnić bieg, ale w większości przypadków nie jest przytłaczający. Ponadto warunkowe przerwy, abyś mógł zbadać, kiedy wydarzyło się coś nieoczekiwanego.
bshirley,

Odpowiedzi:

127

Jednym ze sposobów jest przejście do ustawień kompilacji i w ramach konfiguracji debugowania dodanie wartości do wartości „Preprocessor Macros”, na przykład:

DEBUG_MODE=1

Upewnij się, że robisz to tylko dla konfiguracji debugowania, a nie dla wersji Beta lub Release. Następnie we wspólnym pliku nagłówkowym możesz zrobić coś takiego:

#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

Teraz zamiast NSLog używać DLogwszędzie. Podczas testowania i debugowania otrzymasz komunikaty debugowania. Kiedy jesteś gotowy do wydania wersji beta lub ostatecznej, wszystkie te DLogwiersze automatycznie stają się puste i nic nie jest emitowane. W ten sposób nie ma ręcznego ustawiania zmiennych ani komentowania NSLogswymaganych. Wystarczy wybrać cel kompilacji.

Ramin
źródło
W Xcode 4.5 daje ostrzeżenie, które mówi: „Niejawna deklaracja funkcji 'DLog' jest nieprawidłowa w C99”, więc ta rzecz nie działa.
Sergey Grischyov
2
@SergiusGee: Otrzymujesz niejawne ostrzeżenie o deklaracji, jeśli nie można znaleźć deklaracji funkcji, w takim przypadku myśli, że próbujesz ją zadeklarować. Upewnij się, że Twoja klasa ma dostęp do pliku nagłówkowego, w którym jest to zadeklarowane.
sudo rm -rf
1
Nie rezygnuję z wylogowywania się, ponieważ pozbawia Cię to możliwości otrzymywania lepszych raportów o błędach od użytkowników. użyj rejestrowania asynchronicznego i logLevels, aby ograniczyć wydajność do prawie zera! (patrz cocoa lumberjack lub java's log4j
Daij-Djan
2
Wybrałbym #if zamiast #ifdef, ponieważ DEBUG_MODE 0 nadal będzie podążał prawdziwą ścieżką
Grady Player
1
to nie odpowiada na pytanie
Martin Mlostek
117

Aktualizacja dla Xcode 5 i iOS 7

Uwaga: w przypadku rozwiązania Xcode 7 / Swift 2.1 do usuwania instrukcji print () w kompilacji wydania, moją odpowiedź znajdziesz tutaj .

Tak, powinieneś usunąć wszelkie instrukcje NSLog z kodu wydania, ponieważ spowalnia to twój kod i nie ma żadnego zastosowania w wydanej wersji. Na szczęście w Xcode 5 (iOS 7) niezwykle proste jest usunięcie wszystkich instrukcji NSLog „automatycznie” w kompilacjach wydań. Więc dlaczego tego nie zrobić.

Najpierw 3 kroki do wykonania, a następnie wyjaśnienia

1) w swoim projekcie Xcode znajdź plik „yourProjectName-prefix.pch” (zwykle znajdziesz go w grupie „Support files”), w której znajduje się Twój plik main.m

2) dodaj te 3 wiersze na końcu pliku „.pch”:

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

3) sprawdź różnicę między wersją do debugowania a wersją do wydania. Jednym ze sposobów jest skorzystanie z opcji „edytuj schemat” -> „uruchom nazwę aplikacji” -> w zakładce „informacje” wybierz za pomocą menu rozwijanego między debugowaniem a wydaniem. W wydanej wersji nie zobaczysz żadnych wyników NSLog w konsoli debugowania!

Jak to wszystko działa?

Przede wszystkim trzeba wiedzieć, że preprocesor jest stosunkowo „głupi” i po prostu działa jako „zamiennik tekstu” przed wywołaniem kompilatora. Zastępuje wszystko, co „# zdefiniujesz”, tym, co następuje po #defineinstrukcji.

#define NSLog(...);

(...)Oznacza „coś” między nawiasami (). Zwróć także uwagę ;na koniec. Nie jest to absolutnie konieczne, ponieważ kompilator to zoptymalizuje, ale lubię to tam umieścić, ponieważ jest bardziej „poprawne”. Po naszym #definenie ma „nic”, więc preprocesor zamieni go na „nic”, a więc po prostu wyrzuci całą linię, zaczynając od NSLog...do i włączając ;.

Zdefiniuj instrukcje można uczynić warunkowymi za pomocą #ifdef(jeśli zdefiniowano) lub #ifndef(jeśli nie zdefiniowano)

tutaj piszemy #ifndef DEBUG, co oznacza „jeśli symbol DEBUG nie jest zdefiniowany”. #ifdefAlbo #ifndeftrzeba być „zamknięty” z#endif

Xcode 5 domyślnie definiuje dla nas symbol „DEBUG”, gdy tryb kompilacji to „DEBUG”. W „wersji” nie jest to zdefiniowane. możesz to sprawdzić w ustawieniach projektu, zakładka „Ustawienia kompilacji” -> przewiń w dół do sekcji „Apple LLVM 5.0 - Przetwarzanie wstępne” -> makra preprocesora. Zobaczysz, że symbol „DEBUG” nie jest zdefiniowany dla kompilacji wydań!

na koniec plik .pch jest tworzony automatycznie przez Xcode i automatycznie dołączany do każdego pliku źródłowego podczas kompilacji. To tak, jakbyś umieścił całość #definew każdym z plików źródłowych.

Ronny Webers
źródło
1
Dzięki @Whasssaaahhh, działa świetnie. Uważaj, aby nie umieszczać kodu w instrukcjach dziennika! Preprocesor usunie całe NSLoginstrukcje bez względu na to, co jest w środku.
Eric Platon
1
Jeśli jest to starszy projekt, który nie ma flagi debugowania w preprocessor makrach, należy dodać parametr „debug = 1” dla projektu, a nie celu
Priebe
1
Nie używaj NSLogteż instrukcji if(AllCool) NSLog(@"Cool!Do Nothing!"); else...NSLogif(AllCool) {NSLog(@"Cool!Do Nothing!");} else...
``
33

Niemal wszystkie powyższe odpowiedzi sugerują rozwiązanie, ale nie wyjaśniają problemu. Wyszukałem w google i znalazłem powód. Oto moja odpowiedź:

Tak, jeśli skomentujesz NSLog w swojej wydanej wersji, wydajność będzie lepsza. Ponieważ NSLog działa dość wolno. Czemu? NSLog zrobi dwie rzeczy 1) zapisze komunikaty dziennika do Apple System Logging (ASL), 2) jeśli aplikacja działa w xcode, zapisze również na stderr.

Główny problem tkwi w pierwszym. Aby zapewnić bezpieczeństwo wątków, za każdym razem , gdy wywoływany jest NSLog, otwiera połączenie z narzędziem ASL , wysyła wiadomość i zamyka połączenie. Operacja połączenia jest bardzo droga. Innym powodem jest to, że NSLog poświęca trochę czasu na pobranie sygnatury czasowej do logowania.

Odniesienie stąd .

Andrzej
źródło
23

Moim ulubionym jest używanie wariadycznego makra.

#ifdef NDEBUG
    #define NSLog(...) /* suppress NSLog when in release mode */
#endif
Eytan
źródło
1
Gdzie to położyłeś?
user6631314
20

Oprócz wszystkich osób, które mądrze skomentowały, że nie dzwonienie NSLog()w ogóle w produkcji działa nieco szybciej, dodam, że:

Wszystkie te NSLog()ciągi wyjściowe są widoczne dla każdego, kto pobierze aplikację ze sklepu i uruchomi ją z urządzeniem podłączonym do komputera Mac z uruchomionym Xcode (przez okno Organizatora).

W zależności od tego, jakie informacje rejestrujesz (a zwłaszcza jeśli aplikacja kontaktuje się z serwerem, przeprowadza uwierzytelnianie itp.), Może to być poważny problem z bezpieczeństwem .

Nicolas Miari
źródło
dzięki za info - czy to jest gdzieś w dokumencie, czy właśnie sam to odkryłeś? Czy nadal dotyczy to drukowania w języku Swift?
Ronny Webers
Nie pamiętam, żebym czytał jakąkolwiek dokumentację. Właśnie zainstalowałem moją zarchiwizowaną kompilację (ten sam plik binarny, który przesłałem do sklepu) na moim urządzeniu i podłączyłem ją do Xcode. Nie mam pojęcia, czy to samo dotyczy Swifta print(), ale najprawdopodobniej tak jest.
Nicolas Miari,
@NicolasMiari Co masz na myśli mówiąc, że jest podłączony do Xcode? Jak możemy podłączyć nasz plik binarny do Xcode, właściwie chcę spróbować tego samego. Więc proszę zasugeruj. Dzięki.
iDevAmit
@iDeveloper Mam na myśli pobranie aplikacji z AppStore na urządzenie (np. iPhone), podłączenie tego urządzenia do Xcode przez USB, uruchomienie aplikacji i oglądanie logów w oknie „Urządzenia” Xcode.
Nicolas Miari
3
@Whasssaaahhh print nie jest wyświetlany w konsoli urządzenia .. Właśnie to przetestowałem
Anish Parajuli 웃
13

Domyślne ustawienie projektu

W bieżącym domyślnym ustawieniu projektu w Xcode NS_BLOCK_ASSERTIONSmakro zostanie ustawione na 1 w wersji wydania i DEBUG=1wersji debugowania.

Więc wolę następującą metodę.

// 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
AechoLiu
źródło
5

Tak, powinieneś to wyłączyć. Zwłaszcza jeśli próbujesz zmaksymalizować szybkość swojego kodu. NSLogging rzeczy lewy i prawy zanieczyszcza dziennik systemowy, który inni programiści mogą próbować przekopać i może mieć duży wpływ na kod krytyczny dla szybkości (wewnątrz pętli itp.) Przypadkowo zostawiłem kilka komunikatów dziennika w funkcji rekurencyjnej i muszę wydać aktualizację z „30% wzrostem szybkości!” parę tygodni później... ;-)

Ben Gotow
źródło
5

Wszystkie dobre odpowiedzi, ale oto kolejna mała sztuczka, którą możesz rozważyć, głównie w fazach programowania / testowania aplikacji.

Może to być również przydatne w przypadku kodu wydania aplikacji, jeśli chcesz wyłączyć tylko SWÓJ kod debugowania, a nie komunikaty, które mogą wskazywać na problemy poza bezpośrednią kontrolą kodu.

Sztuczka:

Możesz wyłączyć NSLog dla każdego pliku .m, po prostu dołączając następujący wiersz na górze pliku .m :

#define NSLog(...)

( UWAGA: NIE umieszczaj tego pliku .h, tylko plik .m! )

To po prostu sprawia, że ​​kompilator ocenia NSLog(), rozszerzając zamiast tego makro preprocesora. Makro nie robi nic poza obcinaniem argumentów.

jeśli chcesz go ponownie włączyć, zawsze możesz użyć

#undef NSLog

Możesz na przykład po prostu uniemożliwić wywołanie NSLog wokół określonej grupy metod, wykonując coś takiego jak

#define NSLog(...)
-(void) myProblematicMethodThatSometimesNeedsDebugging {
    ...
}
#undef NSLog
niezsynchronizowane
źródło
3

NSLog jest powolny i nie powinien być używany do kompilacji wydań. Proste makro, takie jak to poniżej, wyłączy je wraz z wszelkimi potwierdzeniami, które możesz mieć, które również powinny być wyłączone. W mniej powszechnym przypadku, gdy potrzebujesz NSLog w kompilacji wydania, po prostu wywołaj go bezpośrednio. Nie zapomnij dodać „-DNDEBUG” do ustawień kompilacji „innych flag c”.

#ifdef NDEBUG
#define MYLog(f, ...) 
#else
#define MYLog(f, ...) NSLog(f, ## __VA_ARGS__)
#endif
papahabla
źródło
2

w pliku pch zapisz to przed #endif

#define NSLog() //
Sandeep Saurabh
źródło
0

a co z tym?

#ifndef DEBUG_MODE
        fclose(stderr);     // the simplest way to disable output from NSLog
#endif    
roberto.buratti
źródło
1
to wyłącza wyjście, ale nie oszczędza czasu przetwarzania, tj. NSLog jest nadal wywoływany, a jego argumenty analizowane
dwery
0
var showDebugLogs = false;

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

Spowoduje to również zaakceptowanie dodatkowych argumentów. Tylko wartość parametru showDebugLogs na true lub false, zgodnie z potrzebami

Zahur
źródło
Jest to miłe, ale nadal występuje problem z całym narzutem wywołań i każdym narzutem (i potencjalnymi efektami ubocznymi) obliczania wszelkich argumentów przekazywanych do Dlogfunkcji.
Todd Lehman