애플리케이션을 출시하기 전에 NSLog를 비활성화해야합니까?


117

iPhone 용 앱을 출시 할 때 비활성화 NSLog();하면 성능이 향상됩니까?


1
현재 프로젝트에서는 UALogger를 사용 합니다 . 그것은 생산에 기록하지 않습니다 당신이하지 명시 적으로 요구하는 경우. 또한 심각도 수준 ( DEBUG , INFO 등)과 같은 일반 NSLog에 비해 다른 이점 이 있습니다. 잘 했어!
Anton Gaenko 2014

1
"성능이 더 좋을까요?"라는 질문에 답하기 위해 예,하지만 얻을 수있는 수익은 NSLog()앱 전체에 걸쳐 얼마나 많은지에 따라 다릅니다 . NSLog()실행하는 데 시간이 걸리고 앱 런타임에 추가 오버 헤드가 추가됩니다. 어쨌든 간단한 DEBUG 전 처리기 매크로로 성능에 도움이된다면 비활성화해야합니다.
스콧

또한 코드에 NSLog / print 문이 많은 경우 디버거에 대해 더 많이 배우는 데 시간을 할애해야한다고 제안 할 수 있습니다. 관심있는 정보를 인쇄하는 중단 점을 정기적으로 설정하고 자동으로 계속합니다. 예, 실행 속도가 약간 느려질 수 있지만 대부분의 경우 압도적이지 않습니다. 또한 조건부 중단을 통해 예기치 않은 일이 발생했을 때 조사 할 수 있습니다.
bshirley

답변:


127

이를 수행하는 한 가지 방법은 빌드 설정으로 이동하여 디버그 구성에서 다음과 같은 "전 처리기 매크로"값에 값을 추가하는 것입니다.

DEBUG_MODE=1

베타 또는 릴리스 버전이 아닌 디버그 구성에 대해서만이 작업을 수행해야합니다. 그런 다음 공통 헤더 파일에서 다음과 같이 할 수 있습니다.

#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에서 유효하지 않습니다."라는 경고를 표시하므로이 작업이 작동하지 않습니다.
Sergey Grischyov

2
@SergiusGee : 함수에 대한 선언을 찾을 수없는 경우 암시 적 선언 경고가 표시되며,이 경우 선언하려고한다고 생각합니다. 클래스가 이것이 선언 된 헤더 파일에 액세스 할 수 있는지 확인하십시오.
sudo rm -rf 2013 년

1
사용자로부터 더 나은 오류 보고서를받을 수있는 기능을 빼앗기므로 로그 아웃을하지 마십시오. 비동기 로깅 및 logLevels를 사용하여 성능 적중을 거의 0으로 제한하십시오! (코코아 나무꾼 또는 자바의 log4j 참조
Daij-Djan 2013

2
DEBUG_MODE 0은 아직 진정한 경로를 통해 들어갈 때 나는 오히려 #ifdef와보다 # 만약에 갈 것
그래 디 플레이어

1
이 질문에 대답하지 않습니다
마틴 Mlostek

117

Xcode 5 및 iOS 7 업데이트

참고 : 릴리스 빌드에서 print () 문 을 제거 하는 Xcode 7 / Swift 2.1 솔루션의 경우 여기에서 내 대답을 찾으 십시오 .

예, 릴리스 코드에서 NSLog 문을 제거해야합니다. 이는 코드 속도를 늦추고 릴리스 버전에서는 사용하지 않기 때문입니다. 다행히 Xcode 5 (iOS 7)에서는 릴리스 빌드에서 모든 NSLog 문을 '자동'으로 제거하는 것이 놀랍도록 간단합니다. 그러니 왜 그렇게하지 마십시오.

먼저 취해야 할 3 단계, 다음 몇 가지 설명

1) Xcode 프로젝트에서 'yourProjectName-prefix.pch'파일을 찾습니다 (일반적으로 main.m 파일이있는 'supporting files'그룹에서 찾을 수 있습니다.

2) '.pch'파일 끝에 다음 3 줄을 추가합니다.

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

3) '디버그'와 '출시'버전의 차이점을 테스트하십시오. 이를 수행하는 한 가지 방법은 '구성표 편집'-> '앱 이름 실행'-> '정보'탭에서 디버그와 릴리스 사이의 드롭 다운 상자를 사용하여 선택하는 것입니다. 릴리스 버전에서는 디버그 콘솔에 NSLog 출력이 표시되지 않습니다!

이 모든 것이 어떻게 작동합니까?

우선, 전처리 기가 상대적으로 '멍청한'것이고 컴파일러가 호출되기 전에 '텍스트 대체자'역할을한다는 것을 알아야합니다. '#define'은 #define명령문 뒤에 오는 것으로 대체 합니다.

#define NSLog(...);

(...)괄호 사이에 '무엇이든'()를 의미합니다. ;끝에 도 마음 . 이것은 컴파일러가 이것을 최적화하기 때문에 꼭 필요한 것은 아니지만 더 '정확'하기 때문에 거기에 두는 것을 좋아합니다. 우리의 후 #define처리기가 '아무것도'로 대체됩니다, 그래서 그것은 단지에서 시작하여 전체 라인을 버리지 않도록, '아무것도'없다 NSLog...때까지와를 포함 ;.

define 문은 #ifdef(정의 된 경우) 또는 #ifndef(정의되지 않은 경우 )를 사용하여 조건부로 만들 수 있습니다.

여기서 우리 #ifndef DEBUG는 '디버그 기호가 정의되지 않은 경우'를 의미합니다. #ifdef또는 #ifndef될 필요가와 '폐쇄'#endif

Xcode 5는 기본적으로 빌드 모드가 'DEBUG'일 때 'DEBUG'기호를 정의합니다. '릴리스'에서는 정의되지 않았습니다. 프로젝트 설정에서 '빌드 설정'탭-> 'Apple LLVM 5.0-전처리'섹션으로 스크롤-> 전 처리기 매크로에서이를 확인할 수 있습니다. 릴리스 빌드에 대해 'DEBUG'기호가 정의되지 않았 음을 알 수 있습니다!

마지막으로 .pch 파일은 Xcode에 의해 자동으로 생성되며 컴파일 시간 동안 모든 소스 파일에 자동으로 포함됩니다. 따라서 #define각 소스 파일에 모든 것을 넣은 것과 같습니다 .


1
감사합니다 @Whasssaaahhh, 훌륭하게 작동합니다. 로그 문에 코드를 넣지 않도록주의하십시오! 전처리 기는 내부 내용을 무시 하고 전체 문 을 제거 합니다 NSLog.
Eric Platon 2014 년

1
프로젝트의 "디버그 = 1"을 추가 importen이 아닌 대상의 preprocesssor 매크로에서 디버그 플래그를 가지고하지 않은 이전 프로젝트의 경우
Priebe

1
또한, 사용하지 않는 NSLog예를 들면, DO 아무것도 문으로 if(AllCool) NSLog(@"Cool!Do Nothing!"); else...대신 팝업 NSLog일부 중괄호if(AllCool) {NSLog(@"Cool!Do Nothing!");} else...
arcady 밥

33

위의 거의 모든 답변은 해결책을 제시하지만 문제를 설명하지는 않습니다. 나는 구글에서 검색을했고 그 이유를 찾았다. 내 대답은 다음과 같습니다.

예, 릴리스 버전에서 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
이거 어디에 두세요?
user6631314

20

NSLog()프로덕션에서 전혀 전화하지 않는 것이 약간 더 빠르게 실행 된다는 현명하게 언급 한 모든 사람들과 더불어 다음과 같이 추가 하겠습니다.

이러한 모든 NSLog()출력 문자열은 스토어에서 앱을 다운로드하고 Xcode를 실행하는 Mac에 연결된 장치로 실행하는 모든 사람에게 표시됩니다 (Organizer 창을 통해).

기록하는 정보에 따라 (특히 앱이 서버에 연결하거나 인증하는 경우 등) 심각한 보안 문제가 될 수 있습니다 .


정보 주셔서 감사합니다-이 문서가 어딘가에 있습니까, 아니면 방금 발견 했습니까? Swift에서 인쇄하는 것이 여전히 사실입니까?
Ronny Webers 2015

문서를 읽은 기억이 없습니다. 방금 보관 된 빌드 (스토어에 제출 한 것과 동일한 바이너리)를 장치에 설치하고 Xcode에 연결했습니다. 나는 그것이 Swift의 경우와 동일한 지 전혀 print()모르겠지만 대부분 그럴 것입니다.
Nicolas Miari 2015

@NicolasMiari Xcode에 연결된다는 것은 무엇을 의미합니까? 바이너리를 Xcode에 연결하는 방법은 실제로 동일하게 시도하고 싶습니다. 그래서 제안하십시오. 감사.
iDevAmit

@iDeveloper AppStore에서 장치 (예 : iPhone)로 앱을 다운로드하고, USB를 통해 해당 장치를 Xcode에 연결하고, 앱을 실행하고 Xcode의 "장치"창에서 로그를 확인합니다.
Nicolas Miari

3
@Whasssaaahhh 인쇄가 장치 콘솔에 출력되지 않습니다. 방금 테스트했습니다.
Anish Parajuli 웃

13

프로젝트 기본 설정

Xcode에서 프로젝트의 현재 기본 설정 내에서 NS_BLOCK_ASSERTIONS매크로는 릴리스 버전과 DEBUG=1디버그 버전에서 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

모든 좋은 대답이 있지만 여기에 주로 앱의 개발 / 테스트 단계에서 사용할 수있는 또 다른 작은 트릭이 있습니다.

또한 코드의 직접 제어를 벗어난 문제를 나타낼 수있는 메시지가 아닌 디버그 코드 만 설정하려는 경우 앱 릴리스 코드에도 유용 할 수 있습니다.

트릭 :

.m 파일 상단에 다음 줄을 포함하여 .m 파일 당 NSLog를 끌 수 있습니다 .

#define NSLog(...)

( 참고 : 않는 NOT 만하는 .m 파일을 이것을 .H 파일을 넣어! )

이렇게하면 컴파일러가 NSLog()대신 전 처리기 매크로를 확장하여 평가 합니다. 매크로는 인수를 제거하는 것 외에는 수행하지 않습니다.

다시 켜고 싶다면 언제든지 사용할 수 있습니다.

#undef NSLog

예를 들어 다음과 같은 작업을 수행하여 특정 메서드 그룹에 대한 NSLog 호출을 방지 할 수 있습니다.

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

3

NSLog는 느리고 릴리스 빌드에 사용하면 안됩니다. 아래의 것과 같은 간단한 매크로는 비활성화해야하는 모든 어설 션과 함께 비활성화합니다. 릴리스 빌드에서 NSLog를 원하는 덜 일반적인 경우에는 직접 호출하십시오. "기타 c 플래그"빌드 설정에 "-DNDEBUG"를 추가하는 것을 잊지 마십시오.

#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함수에 전달 된 인수를 계산하는 오버 헤드 (및 잠재적 인 부작용)의 문제가 있습니다.
Todd Lehman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.