Uygulamayı yayınlamadan önce NSLog'u devre dışı bırakmam gerekir mi?


117

İPhone için bir uygulama yayınlarken, devre dışı bırakırsam NSLog();daha iyi performans gösterir mi?


1
Mevcut projemde UALogger kullanıyorum . Açıkça sormazsanız, üretimde oturum açmaz . Ve basit NSLog'a göre kutudan çıkan önem seviyeleri ( DEBUG , INFO vb. İle) gibi başka faydaları da vardır . Aferin!
Anton Gaenko

1
Sorunuzu "daha iyi performans gösterecek mi?" Evet öyle, ancak elde edeceğiniz getiri NSLog(), uygulamanızda kaç tane olduğuna bağlıdır . NSLog()yürütmek zaman alır ve uygulamanızın çalışma süresine ek yük getirir. Her neyse, basit bir DEBUG önişlemci makrosuyla performansa yardımcı oluyorsa, onu devre dışı bırakmalıyız.
Scott

Ayrıca, kodunuzda çok sayıda NSLog / print ifadesi varsa, hata ayıklayıcı hakkında daha fazla şey öğrenmek için biraz zaman harcamanızı önerebilirim. İlgilendiğim bilgileri yazdıran ve otomatik olarak devam eden kesme noktaları düzenli olarak belirlerim. Evet, yavaşlamayı biraz yavaşlatabilir, ancak çoğu durumda bunaltıcı değildir. Ayrıca, beklenmedik bir şeyin ne zaman olduğunu araştırabilmeniz için koşullu aralar.
bshirley

Yanıtlar:


127

Bunu yapmanın bir yolu, Derleme ayarlarınıza gitmek ve Hata Ayıklama yapılandırması altında "Önişlemci Makroları" değerine aşağıdaki gibi bir değer eklemektir:

DEBUG_MODE=1

Bunu Beta veya Sürüm sürümleri için değil, yalnızca Hata Ayıklama yapılandırması için yaptığınızdan emin olun. Daha sonra ortak bir başlık dosyasında aşağıdaki gibi bir şey yapabilirsiniz:

#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

Şimdi her yerde NSLog kullanmak yerine DLog. Test ederken ve hata ayıklarken, hata ayıklama mesajları alırsınız. Bir beta veya son sürümü yayınlamaya hazır olduğunuzda, tüm bu DLogsatırlar otomatik olarak boş olur ve hiçbir şey yayınlanmaz. Bu şekilde, değişkenlerin manuel olarak ayarlanması veya yorumlanması NSLogsgerekmez. İnşa hedefinizi seçmek bununla ilgilenir.


Xcode 4.5'te "DLog 'işlevinin örtük bildirimi C99'da geçersiz" şeklinde bir uyarı verir, bu yüzden bu şey çalışmaz.
Sergey Grischyov

2
@SergiusGee: İşlevin bildirimi bulunamazsa örtük bildirim uyarısı alırsınız, bu durumda bildirmeye çalıştığınızı düşünür. Sınıfınızın, bunun bildirildiği başlık dosyasına erişimi olduğundan emin olun.
sudo rm -rf

1
Kullanıcılardan daha iyi hata raporları alma yeteneğinizi ortadan kaldırdığı için oturumu kapatmayın. performans vuruşunu neredeyse sıfıra sınırlamak için eşzamansız günlük kaydı ve logLevels kullanın! (bkz. kakao oduncu veya
java'nın

2
DEBUG_MODE 0 hala doğru yoldan gideceğinden #ifdef yerine #if ile giderdim
Grady Player

1
bu soruya cevap vermiyor
Martin Mlostek

117

Xcode 5 ve iOS 7 için güncelleme

not: bir sürüm yapısındaki print () ifadelerini kaldırmaya yönelik bir Xcode 7 / Swift 2.1 çözümü için cevabımı burada bulun .

Evet, kodunuzu yavaşlattığı ve yayın sürümünde herhangi bir faydası olmadığı için yayın kodunuzdaki tüm NSLog ifadelerini kaldırmalısınız. Neyse ki, Xcode 5'te (iOS 7), sürüm yapılarında tüm NSLog ifadelerinizi 'otomatik olarak' kaldırmak inanılmaz derecede kolaydır. Öyleyse neden yapmıyorsun?

Önce atılması gereken 3 adım, ardından bazı açıklamalar

1) Xcode projenizde 'yourProjectName-prefix.pch' dosyasını bulun (normalde bunu main.m dosyanızın bulunduğu 'destekleyici dosyalar' grubu altında bulacaksınız.

2) ".pch" dosyasının sonuna şu 3 satırı ekleyin:

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

3) 'hata ayıklama' ve 'yayın' sürümünüz arasındaki farkı test edin. Bunu yapmanın bir yolu, 'düzeni düzenle' -> 'uygulama adını çalıştır' -> 'bilgi' sekmesi altında, hata ayıklama ve yayınlama arasındaki açılır kutuyu kullanarak seçim yapmaktır. Yayın sürümünde, hata ayıklama konsolunda herhangi bir NSLog çıktısı görmeyeceksiniz!

Bütün bunlar nasıl çalışıyor?

her şeyden önce, bir önişlemcinin görece 'aptal' olduğunu ve derleyici çağrılmadan önce sadece bir 'metin ikame' görevi gördüğünü bilmek gerekir. '# Tanımladığınız' her şeyi #defineifadeden sonra gelenle değiştirir .

#define NSLog(...);

(...)Parantez 'şey' () anlamına gelir. ;Sonuna da dikkat edin . Derleyici bunu ortadan kaldıracağından bu kesinlikle gerekli değildir, ancak daha 'doğru' olduğu için onu oraya koymaktan hoşlanırım. Kızımız sonra #defineönişlemci 'hiçbir şey' ile değiştirecektir, ve bu yüzden sadece başlayarak tam bir çizgi atmak böylece, 'yok' yok NSLog...dek dahil ;.

Tanımlama ifadeleri kullanılarak #ifdef(tanımlanmışsa) veya #ifndef( tanımlanmamışsa) koşullu yapılabilir

burada yazıyoruz #ifndef DEBUG, bunun anlamı 'DEBUG sembolü tanımlı değilse'. #ifdefVeya #ifndefolmaya gerek ile 'kapalı'#endif

Xcode 5, derleme modu 'DEBUG' olduğunda bizim için varsayılan olarak 'DEBUG' sembolünü tanımlar. "Sürümde" bu tanımlanmamıştır. bunu proje ayarlarınızdan doğrulayabilirsiniz, 'Yapı ayarları' sekmesi -> 'Apple LLVM 5.0 - Önişleme' -> önişlemci makroları bölümüne gidin. 'DEBUG' sembolünün sürüm yapıları için tanımlanmadığını göreceksiniz!

son olarak, .pch dosyası Xcode tarafından otomatik olarak oluşturulur ve derleme sırasında her kaynak dosyaya otomatik olarak eklenir. Yani, her #defineşeyi kaynak dosyalarınızın her birine yerleştirmişsiniz gibi.


1
Teşekkürler @ Whasssaaahhh, harika çalışıyor. Günlük ifadelerine kod koymamaya dikkat edin! Önişlemci , içeride ne olduğunu göz ardı ederek tüm ifadeleri kaldıracaktırNSLog .
Eric Platon

1
Önişlemci veya makrolarda hata ayıklama bayrağına sahip olmayan daha eski bir projeyse, hedef değil proje için "debug = 1" eklemek için
Priebe

1
Ayrıca kullanmayın NSLogörneğin bir do hiçbir şey ifadesi olarak if(AllCool) NSLog(@"Cool!Do Nothing!"); else...yerine pop NSLogbazı kıvırcık parantez içindeif(AllCool) {NSLog(@"Cool!Do Nothing!");} else...
arcady bob

33

Hemen hemen yukarıdaki yanıtların tümü bir çözüm öneriyor ancak sorunu açıklamıyor. Google'da bir arama yaptım ve sebebini buldum. İşte cevabım:

Evet, yayın sürümünüzde NSLog hakkında yorum yaparsanız, performans daha iyi hale gelecektir. NSLog oldukça yavaş olduğu için. Neden? NSLog iki şey yapar 1) günlük mesajlarını Apple Sistem Günlüğü'ne (ASL) yazar, 2) uygulama xcode'da çalışıyorsa stderr'e de yazar.

Esas sorun ilkinde yatıyor. İş parçacığı güvenliğini sağlamak için, NSLog her çağrıldığında ASL tesisine bir bağlantı açar , mesaj gönderir ve bağlantıyı kapatır. Bağlantı işlemi çok pahalıdır. Diğer bir neden de NSLog'un günlüğe kaydedilecek zaman damgasını almak için biraz zaman harcamasıdır.

Buradan referans .


23

Benim kişisel favorim, değişken bir makro kullanmaktır.

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

1
Bunu nereye koyuyorsunuz?
user6631314

20

NSLog()Üretimde hiç arama yapmamanın biraz daha hızlı olduğunu akıllıca yorumlayan tüm insanlara ek olarak şunu ekleyeceğim:

Tüm bu NSLog()çıktı dizeleri, uygulamanızı mağazadan indiren ve Xcode çalıştıran bir mac'a bağlı cihazla çalıştıran herkes tarafından görülebilir (Düzenleyici penceresi aracılığıyla).

Hangi bilgileri kaydettiğinize bağlı olarak (ve özellikle uygulamanız bir sunucuyla iletişim kuruyorsa, kimlik doğrulaması yapıyorsa vb.), Bu ciddi bir güvenlik sorunu olabilir .


bilgi için teşekkürler - bu belgede bir yerde mi yoksa sadece kendin mi keşfetti? Swift'deki baskı için hala doğru mu?
Ronny Webers

Herhangi bir belge okuduğumu hatırlamıyorum. Arşivlenmiş yapımı (mağazaya gönderdiğim ikili dosyanın aynısını) cihazıma yükledim ve Xcode'a taktım. Swift'inki için de aynı olup olmadığı hakkında hiçbir fikrim yok print(), ama büyük olasılıkla öyle.
Nicolas Miari

@NicolasMiari Xcode'a takılmakla ne demek istiyorsun? İkili dosyamızı Xcode'a nasıl bağlayabiliriz, aslında aynısını denemek istiyorum. Bu yüzden lütfen önerin. Teşekkürler.
iDevAmit

@iDeveloper Uygulamanızı AppStore'dan bir cihaza (örneğin bir iPhone) indirmek, bu cihazı USB aracılığıyla Xcode'a bağlamak, uygulamanızı başlatmak ve Xcode'un "Cihazlar" penceresinde günlükleri izlemek demek istiyorum.
Nicolas Miari

3
@Whasssaaahhh baskısı cihaz konsolunda
çıkmıyor ... Bunu

13

Proje Varsayılan Ayarı

Xcode'daki mevcut varsayılan proje ayarı içinde, NS_BLOCK_ASSERTIONSmakro yayın sürümünde ve DEBUG=1Hata Ayıklama sürümünde 1 olarak ayarlanacaktır .

Bu yüzden aşağıdaki yöntemi tercih ediyorum.

// 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

Evet, devre dışı bırakmalısınız. Özellikle kodunuzun hızını en üst düzeye çıkarmaya çalışıyorsanız. NSLogging şeyler, diğer geliştiricilerin kazmaya çalıştıkları sistem günlüğünü kirletir ve hız açısından kritik kod üzerinde büyük bir etkisi olabilir (döngülerin içinde vb.) Yanlışlıkla bazı günlük mesajlarını bir kez özyinelemeli bir işlevde bıraktım "% 30 hız artışı" içeren bir güncelleme yayınlamalısınız! birkaç hafta sonra... ;-)


5

Tüm iyi yanıtlar, ancak işte, esas olarak uygulamanızın geliştirme / test aşamalarında kullanmayı düşünebileceğiniz başka bir küçük numara.

Ayrıca, yalnızca hata ayıklama kodunuzu çevirmek istiyorsanız ve kodunuzun doğrudan kontrolü dışındaki sorunları gösterebilecek mesajları değil, uygulama sürüm kodu için de yararlı olabilir.

Numara:

.M dosyası başına NSLog'u, .m dosyasının üst kısmına aşağıdaki satırı ekleyerek kapatabilirsiniz :

#define NSLog(...)

( NOT: bunu .h dosyasını YERLEŞTİRMEYİN , sadece .m dosyasını! )

Bu sadece derleyicinin değerlendirmesini sağlar NSLog() bunun yerine önişlemci makronuzu genişleterek . Makro, argümanları çıkarmaktan başka bir şey yapmaz.

tekrar açmak isterseniz her zaman kullanabilirsiniz

#undef NSLog

Örneğin, belirli bir yöntem grubu etrafında NSLog'a yapılan çağrıları, aşağıdaki gibi bir şey yaparak engelleyebilirsiniz:

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

3

NSLog yavaştır ve sürüm yapıları için kullanılmamalıdır. Aşağıdaki gibi basit bir makro, sahip olabileceğiniz ve devre dışı bırakılması gereken tüm iddialarla birlikte onu devre dışı bırakacaktır. NSLog'un bir sürüm yapısında olmasını istediğiniz daha az yaygın durumda, doğrudan çağırmanız yeterlidir. "Diğer c bayrakları" oluşturma ayarlarınıza "-DNDEBUG" eklemeyi unutmayın.

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


0

Peki buna ne dersin?

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

1
bu çıktıyı devre dışı bırakır, ancak herhangi bir işlem süresinden tasarruf etmez, yani NSLog hala çağrılır ve argümanları çözümlenir
dwery

0
var showDebugLogs = false;

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

Bu, ek bağımsız değişkenleri de kabul eder .. İhtiyacınıza göre yalnızca showDebugLogs parametre değeri doğru veya yanlış olarak ayarlanır


Bu güzel, ancak yine de tüm çağrı ek yükü ve Dlogişleve iletilen herhangi bir argümanı hesaplamanın ek yükü (ve olası yan etkileri) sorunu var .
Todd Lehman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.