Tôi có cần phải tắt NSLog trước khi phát hành Ứng dụng không?


117

Khi phát hành một ứng dụng cho iPhone, nếu tôi tắt NSLog();nó có hoạt động tốt hơn không?


1
Trong dự án hiện tại của tôi, tôi sử dụng UALogger . Nó không đăng nhập sản xuất , nếu bạn không hỏi nó một cách rõ ràng. Và có các lợi ích khác so với NSLog đơn thuần như mức độ nghiêm trọng (với GỠ LỖI , THÔNG TIN và v.v.) ngoài hộp. Làm tốt lắm!
Anton Gaenko

1
Để trả lời câu hỏi của bạn về "nó sẽ hoạt động tốt hơn?" Có, nhưng lợi nhuận mà bạn nhận được phụ thuộc vào số lượng NSLog()bạn có trên ứng dụng của mình. NSLog()cần thời gian để thực thi và thêm chi phí bổ sung vào thời gian chạy ứng dụng của bạn. Dù sao đi nữa, nếu nó giúp ích cho hiệu suất với macro tiền xử lý DEBUG đơn giản, thì chúng ta nên vô hiệu hóa nó.
Scott

Tôi cũng sẽ đề xuất nếu bạn có nhiều câu lệnh NSLog / print trong mã của mình, điều đó có thể gợi ý bạn nên dành một chút thời gian để tìm hiểu thêm về trình gỡ lỗi. Tôi thường xuyên đặt các điểm ngắt in thông tin tôi quan tâm và tự động tiếp tục. Có, nó có thể làm chậm quá trình chạy một chút, nhưng trong hầu hết các trường hợp, nó không quá tải. Ngoài ra, nghỉ có điều kiện để bạn có thể điều tra khi có điều gì đó không mong muốn xảy ra.
bshirley

Câu trả lời:


127

Một cách để làm điều đó là vào cài đặt Bản dựng của bạn và trong cấu hình Gỡ lỗi, hãy thêm giá trị vào giá trị "Macro tiền xử lý" như:

DEBUG_MODE=1

Đảm bảo rằng bạn chỉ thực hiện việc này cho cấu hình Gỡ lỗi chứ không phải cho các phiên bản Beta hoặc Release. Sau đó, trong một tệp tiêu đề chung, bạn có thể thực hiện một số việc như:

#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

Bây giờ thay vì NSLog sử dụng DLogở mọi nơi. Khi kiểm tra và gỡ lỗi, bạn sẽ nhận được thông báo gỡ lỗi. Khi bạn sẵn sàng phát hành bản beta hoặc bản phát hành cuối cùng, tất cả các DLogdòng đó sẽ tự động trở nên trống và không có gì được phát ra. Bằng cách này, không cần cài đặt thủ công các biến hoặc nhận xét NSLogscần thiết. Chọn mục tiêu xây dựng của bạn sẽ giải quyết nó.


Trong Xcode 4.5, nó đưa ra một cảnh báo rằng: "Khai báo ngầm định của hàm 'DLog' không hợp lệ trong C99" vì vậy điều này không hoạt động.
Sergey Grischyov

2
@SergiusGee: Bạn nhận được cảnh báo khai báo ngầm nếu không tìm thấy khai báo cho hàm, trong trường hợp đó nó cho rằng bạn đang cố gắng khai báo. Đảm bảo rằng lớp của bạn có quyền truy cập vào tệp tiêu đề nơi điều này được khai báo.
sudo rm -rf

1
Tôi không đăng xuất vì nó cướp đi khả năng nhận báo cáo lỗi tốt hơn từ người dùng của bạn. sử dụng ghi nhật ký không đồng bộ và logLevels để giới hạn hiệu suất đạt được gần như bằng không! (xem ca cao lumberjack hoặc java's log4j
Daij-Djan,

2
Tôi sẽ đi với #if hơn là #ifdef, vì DEBUG_MODE 0 sẽ vẫn đi theo con đường thực sự
Grady Player

1
điều này không trả lời câu hỏi
Martin Mlostek

117

Cập nhật cho Xcode 5 và iOS 7

lưu ý: đối với giải pháp Xcode 7 / Swift 2.1 để loại bỏ các câu lệnh print () trong bản phát hành, hãy tìm câu trả lời của tôi tại đây .

Có, bạn nên xóa bất kỳ câu lệnh NSLog nào trong mã phát hành của mình, vì nó chỉ làm chậm mã của bạn và không có ích trong phiên bản phát hành. May mắn thay, trong Xcode 5 (iOS 7), việc loại bỏ tất cả các câu lệnh NSLog của bạn 'tự động' trong các bản dựng phát hành rất đơn giản. Vậy tại sao lại không làm.

Đầu tiên là 3 bước cần thực hiện, sau đó là một số giải thích

1) trong dự án Xcode của bạn, tìm tệp 'yourProjectName-prefix.pch' (thông thường bạn sẽ tìm thấy tệp này trong nhóm 'tệp hỗ trợ', nơi chứa tệp main.m của bạn

2) thêm 3 dòng này vào cuối tệp '.pch':

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

3) kiểm tra sự khác biệt giữa phiên bản 'gỡ lỗi' và 'phát hành' của bạn. Một cách để làm điều này là thông qua 'chỉnh sửa lược đồ' -> 'chạy tên ứng dụng' -> trong tab 'thông tin', chọn bằng cách sử dụng hộp thả xuống giữa gỡ lỗi và phát hành. Trong phiên bản phát hành, bạn sẽ không thấy bất kỳ đầu ra NSLog nào trong bảng điều khiển gỡ lỗi!

Làm thế nào để tất cả điều này hoạt động?

trước hết, người ta phải biết rằng một bộ tiền xử lý tương đối 'ngu ngốc', và chỉ hoạt động như một 'bộ thay thế văn bản' trước khi trình biên dịch được gọi. Nó thay thế bất kỳ thứ gì bạn '#define' bằng những gì sau #definecâu lệnh.

#define NSLog(...);

Viết (...)tắt của 'bất cứ thứ gì' giữa dấu ngoặc (). Tâm trí cũng ;là cuối cùng. Điều này không hoàn toàn cần thiết vì trình biên dịch sẽ tối ưu hóa điều này đi, nhưng tôi muốn đặt nó ở đó, vì nó 'chính xác' hơn. Sau khi của chúng ta #definelà 'không có gì', vì vậy bộ tiền xử lý sẽ thay thế nó bằng 'không có gì', và do đó, nó sẽ loại bỏ dòng hoàn chỉnh, bắt đầu từ NSLog...cho đến khi và bao gồm; .

câu lệnh xác định có thể được thực hiện có điều kiện bằng cách sử dụng #ifdef(nếu được định nghĩa) hoặc#ifndef (nếu không được định nghĩa)

ở đây chúng tôi viết #ifndef DEBUG, có nghĩa là 'nếu ký hiệu DEBUG không được xác định'. các #ifdefhoặc#ifndef cần phải 'đóng' với#endif

Xcode 5 xác định theo mặc định biểu tượng 'GỠ LỖI' cho chúng tôi khi chế độ xây dựng là 'GỢI Ý'. Trong 'phát hành', điều này không được xác định. bạn có thể xác minh điều này trong cài đặt dự án của mình, tab 'Cài đặt bản dựng' -> cuộn xuống phần 'Apple LLVM 5.0 - Tiền xử lý' -> macro tiền xử lý. Bạn sẽ thấy rằng ký hiệu 'GỠ LỖI' không được xác định cho các bản phát hành!

cuối cùng, tệp .pch được Xcode tạo tự động và tự động được đưa vào mọi tệp nguồn trong thời gian biên dịch. Vì vậy, nó giống như thể bạn đã đặt toàn bộ #definevào mỗi tệp nguồn của mình.


1
Cảm ơn @Whasssaaahhh, nó hoạt động rất tốt. Hãy cẩn thận để tránh đặt mã trong các báo cáo nhật ký! Bộ tiền xử lý sẽ loại bỏ toàn bộ các NSLogcâu lệnh mà không quan tâm đến những gì bên trong.
Eric Platon

1
Nếu đó là một dự án cũ hơn không có cờ gỡ lỗi trong macro trình xử lý trước, nó sẽ importen để thêm "debug = 1" cho dự án chứ không phải mục tiêu
Priebe

1
Ngoài ra, không sử dụng NSLognhư một tuyên bố không có gì làm, ví dụ như if(AllCool) NSLog(@"Cool!Do Nothing!"); else...thay vì bật NSLogtrong một số dấu ngoặc nhọnif(AllCool) {NSLog(@"Cool!Do Nothing!");} else...
bob arcady

33

Hầu như tất cả các câu trả lời trên đều là một giải pháp nhưng không giải thích được vấn đề. Tôi đã tìm kiếm trên google và tìm ra lý do. Đây là câu trả lời của tôi:

Có, nếu bạn nhận xét NSLog trong phiên bản phát hành của mình, hiệu suất sẽ trở nên tốt hơn. Vì NSLog khá chậm. Tại sao? NSLog sẽ thực hiện hai việc 1) ghi thông báo nhật ký vào Apple System Logging (ASL), 2) nếu ứng dụng chạy bằng xcode, nó cũng ghi vào stderr.

Vấn đề chính nằm ở vấn đề đầu tiên. Để đạt được sự an toàn của luồng, mỗi khi NSLog được gọi, nó sẽ mở một kết nối đến cơ sở ASL , gửi tin nhắn và đóng kết nối. Hoạt động kết nối rất tốn kém. Một lý do khác là NSLog dành một ít thời gian để lấy dấu thời gian để ghi nhật ký.

Tham khảo từ đây .


23

Yêu thích cá nhân của tôi là sử dụng một macro đa dạng.

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

1
Bạn đặt cái này ở đâu?
user6631314

20

Ngoài tất cả những người đã nhận xét một cách khôn ngoan rằng không gọi điện NSLog()trong quá trình sản xuất chạy nhanh hơn một chút, tôi sẽ nói thêm rằng:

Tất cả các NSLog()chuỗi đầu ra đó sẽ hiển thị cho bất kỳ ai tải xuống ứng dụng của bạn từ cửa hàng và chạy ứng dụng đó với thiết bị được cắm vào máy mac chạy Xcode (thông qua cửa sổ Organizer).

Tùy thuộc vào thông tin bạn đăng nhập (và đặc biệt nếu ứng dụng của bạn liên hệ với máy chủ, xác thực, v.v.), đây có thể là một vấn đề bảo mật nghiêm trọng .


cảm ơn vì thông tin - điều này có trong tài liệu ở đâu đó, hay bạn vừa khám phá ra? Nó có còn đúng với bản in trong Swift không?
Ronny Webers

Tôi không nhớ đã đọc bất kỳ tài liệu nào. Tôi vừa cài đặt bản dựng đã lưu trữ của mình (cùng bản nhị phân mà tôi đã gửi cho cửa hàng) trên thiết bị của mình và cắm nó vào Xcode. Tôi không biết nó có giống với Swift không print(), nhưng rất có thể là như vậy.
Nicolas Miari

@NicolasMiari Bạn có nghĩa là gì khi cắm vào Xcode? Làm cách nào chúng ta có thể cắm mã nhị phân của mình vào Xcode, thực sự thì tôi cũng muốn thử như vậy. Vì vậy, xin đề nghị. Cảm ơn.
iDevAmit

@iDeveloper Ý tôi là tải ứng dụng của bạn từ AppStore xuống một thiết bị (ví dụ: iPhone), cắm thiết bị đó với Xcode qua USB, khởi chạy ứng dụng của bạn và xem nhật ký trong cửa sổ "Thiết bị" của Xcode.
Nicolas Miari

3
@Whasssaaahhh bản in không xuất ra trong bảng điều khiển thiết bị..tôi vừa kiểm tra điều đó
Anish Parajuli 웃

13

Cài đặt mặc định của dự án

Bên trong cài đặt mặc định hiện tại của dự án trong Xcode, NS_BLOCK_ASSERTIONSmacro sẽ được đặt thành 1 trong phiên bản phát hành và DEBUG=1trong phiên bản Gỡ lỗi.

Vì vậy, tôi thích phương pháp sau hơn.

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

Có, bạn nên vô hiệu hóa nó. Đặc biệt nếu bạn đang cố gắng tối đa hóa tốc độ mã của mình. NSLogging những thứ bên trái và bên phải gây ô nhiễm nhật ký hệ thống mà các nhà phát triển khác có thể đang cố gắng đào sâu và nó có thể có tác động lớn đến mã quan trọng về tốc độ (vòng lặp bên trong, v.v.) Tôi đã vô tình để lại một số thông báo nhật ký trong một hàm đệ quy một lần và phải phát hành bản cập nhật với tốc độ "tăng 30%!" một vài tuần sau đó... ;-)


5

Tất cả các câu trả lời đều tốt, tuy nhiên đây là một mẹo nhỏ khác mà bạn có thể cân nhắc sử dụng, chủ yếu trong giai đoạn phát triển / thử nghiệm ứng dụng của mình.

Nó cũng có thể hữu ích cho mã phát hành ứng dụng, nếu bạn chỉ muốn chuyển mã gỡ lỗi của BẠN chứ không phải các thông báo có thể chỉ ra các vấn đề nằm ngoài tầm kiểm soát trực tiếp của mã của bạn.

Thủ thuật:

Bạn có thể tắt NSLog cho mỗi tệp .m bằng cách chỉ cần thêm dòng sau vào đầu tệp .m :

#define NSLog(...)

( LƯU Ý: KHÔNG đặt tệp này là tệp .h, chỉ tệp .m! )

Điều này chỉ làm cho trình biên dịch đánh giá NSLog()bằng cách mở rộng macro bộ xử lý trước của bạn. Macro không làm gì khác ngoài việc loại bỏ các đối số.

nếu bạn muốn bật lại nó, bạn luôn có thể sử dụng

#undef NSLog

Ví dụ, bạn có thể chỉ cần ngăn chặn các lệnh gọi đến NSLog xung quanh một nhóm phương thức cụ thể bằng cách thực hiện một số việc như

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

3

NSLog chậm và không nên được sử dụng cho các bản phát hành. Một macro đơn giản như dưới đây sẽ vô hiệu hóa nó cùng với bất kỳ xác nhận nào bạn có thể có cũng sẽ bị vô hiệu hóa. Trong trường hợp ít phổ biến hơn khi bạn muốn NSLog trong một bản phát hành, chỉ cần gọi nó trực tiếp. Đừng quên thêm "-DNDEBUG" vào cài đặt xây dựng "cờ c khác" của bạn.

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


0

cái này thì sao?

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

1
điều này vô hiệu hóa kết quả đầu ra, nhưng không tiết kiệm bất kỳ thời gian xử lý nào, tức là NSLog vẫn được gọi và các đối số của nó được phân tích cú pháp
dwery

0
var showDebugLogs = false;

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

Điều này cũng sẽ chấp nhận các đối số bổ sung .. Chỉ cần giá trị tham số showDebugLogs thành true hoặc false, tùy theo nhu cầu của bạn


Điều này rất hay, nhưng vẫn có vấn đề về tất cả chi phí cuộc gọi và mọi chi phí (và các tác dụng phụ tiềm ẩn) của việc tính toán bất kỳ đối số nào được truyền cho Dloghàm.
Todd Lehman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.