ฉันจำเป็นต้องปิดการใช้งาน NSLog ก่อนปล่อยแอปพลิเคชันหรือไม่


117

ตอนปล่อยแอพสำหรับ iPhone ถ้าปิดNSLog();จะทำงานดีขึ้นไหม


1
ในโครงการปัจจุบันของผมใช้UALogger มันไม่ได้เข้าสู่ระบบในการผลิตถ้าคุณไม่ถามอย่างชัดเจน และมีประโยชน์อื่น ๆ เหนือ NSLog ธรรมดาเช่นระดับความรุนแรง (พร้อมDEBUG , INFOและอื่น ๆ ) นอกกรอบ เก่งมาก!
Anton Gaenko

1
หากต้องการตอบคำถามของคุณเรื่อง "จะทำงานได้ดีขึ้นหรือไม่" ใช่ แต่ผลตอบแทนที่คุณได้รับนั้นขึ้นอยู่กับจำนวนที่NSLog()คุณมีในแอปของคุณ NSLog()ต้องใช้เวลาในการดำเนินการและเพิ่มค่าใช้จ่ายเพิ่มเติมให้กับรันไทม์ของแอปของคุณ อย่างไรก็ตามหากช่วยในการทำงานด้วยมาโครตัวประมวลผลล่วงหน้า DEBUG ที่เรียบง่ายเราควรปิดการใช้งาน
Scott

ฉันขอแนะนำด้วยว่าคุณมีคำสั่ง NSLog / print จำนวนมากในโค้ดของคุณหรือไม่อาจแนะนำให้คุณใช้เวลาเรียนรู้เพิ่มเติมเกี่ยวกับดีบักเกอร์ ฉันตั้งค่าเบรกพอยต์เป็นประจำเพื่อพิมพ์ข้อมูลที่ฉันสนใจและดำเนินการต่อโดยอัตโนมัติ ใช่มันอาจทำให้การวิ่งช้าลงเล็กน้อย แต่ในกรณีส่วนใหญ่มันจะไม่ท่วมท้น นอกจากนี้การแบ่งตามเงื่อนไขเพื่อให้คุณสามารถตรวจสอบเมื่อมีสิ่งที่ไม่คาดคิดเกิดขึ้น
bshirley

คำตอบ:


127

วิธีหนึ่งที่จะทำได้คือเข้าไปที่การตั้งค่า Build ของคุณและภายใต้การกำหนดค่าการดีบักให้เพิ่มค่าเป็นค่า "Preprocessor Macros" เช่น:

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

1
รหัสจะไม่ออกจากระบบเนื่องจากจะทำให้คุณไม่สามารถรับรายงานข้อผิดพลาดที่ดีขึ้นจากผู้ใช้ ใช้การบันทึกแบบ async และ logLevels เพื่อ จำกัด ประสิทธิภาพการทำงานให้เกือบเป็นศูนย์! (ดูคนตัดไม้โกโก้หรือ log4j ของ java
Daij-Djan

2
ฉันจะไปกับ #if แทนที่จะเป็น #ifdef เนื่องจาก DEBUG_MODE 0 จะยังคงผ่านเส้นทางที่แท้จริง
Grady Player

1
สิ่งนี้ไม่ตอบคำถาม
Martin Mlostek

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) ทดสอบความแตกต่างระหว่างเวอร์ชัน 'debug' และ 'release' วิธีหนึ่งในการดำเนินการนี้คือการใช้ "แก้ไขแบบแผน" -> "เรียกใช้ชื่อแอป" -> ใต้แท็บ "ข้อมูล" ให้เลือกโดยใช้ช่องแบบเลื่อนลงระหว่างการดีบักและการเปิดตัว ในเวอร์ชันรีลีสคุณจะไม่เห็นเอาต์พุต NSLog ในคอนโซลการแก้ปัญหา!

ทั้งหมดนี้ทำงานอย่างไร?

ก่อนอื่นเราต้องรู้ว่าพรีโปรเซสเซอร์ค่อนข้าง 'โง่' และทำหน้าที่เป็น 'ตัวแทนที่ข้อความ' ก่อนที่คอมไพเลอร์จะถูกเรียกใช้ มันแทนที่ทุกสิ่งที่คุณ '#define' ด้วยสิ่งที่ตามมาใน#defineข้อความ

#define NSLog(...);

(...)ยืนสำหรับ 'อะไร' ระหว่างวงเล็บ () ใจยัง;ในตอนท้าย สิ่งนี้ไม่จำเป็นอย่างยิ่งเนื่องจากคอมไพเลอร์จะปรับให้เหมาะสมที่สุด แต่ฉันชอบใส่ไว้ที่นั่นเพราะมัน 'ถูกต้อง' มากกว่า หลังจากของเรา#defineไม่มี 'อะไร' ดังนั้นตัวประมวลผลก่อนจะแทนที่ด้วย 'nothing' ดังนั้นมันจะทิ้งบรรทัดที่สมบูรณ์โดยเริ่มที่NSLog...จนกระทั่งและรวมถึง;.

กำหนดคำสั่งสามารถกำหนดเงื่อนไขโดยใช้#ifdef(ถ้ากำหนด) หรือ#ifndef(ถ้าไม่ได้กำหนดไว้)

ที่นี่เราเขียน#ifndef DEBUGซึ่งหมายความว่า 'หากไม่ได้กำหนดสัญลักษณ์ DEBUG' #ifdefหรือ#ifndefจำเป็นที่จะต้อง 'ปิด' ด้วย#endif

Xcode 5 กำหนดสัญลักษณ์ 'DEBUG' สำหรับเราโดยค่าเริ่มต้นเมื่อโหมด de build คือ 'DEBUG' ใน 'release' ไม่ได้กำหนดไว้ คุณสามารถตรวจสอบได้ภายใต้การตั้งค่าโปรเจ็กต์แท็บ 'สร้างการตั้งค่า' -> เลื่อนลงไปที่ส่วน 'Apple LLVM 5.0 - Preprocessing' -> มาโครตัวประมวลผลล่วงหน้า คุณจะเห็นว่าสัญลักษณ์ 'DEBUG' ไม่ได้ถูกกำหนดไว้สำหรับรุ่นที่วางจำหน่าย!

สุดท้ายไฟล์. pch จะถูกสร้างขึ้นโดย Xcode โดยอัตโนมัติและรวมอยู่ในไฟล์ต้นฉบับทุกไฟล์โดยอัตโนมัติในช่วงเวลารวบรวม ดังนั้นจึงเหมือนกับว่าคุณจะใส่ข้อมูลทั้งหมด#defineลงในไฟล์ต้นฉบับแต่ละไฟล์


1
ขอบคุณ @Whasssaaahhh มันใช้งานได้ดี ระวังอย่าใส่รหัสในคำสั่งบันทึก! พรีโปรเซสเซอร์จะลบข้อความทั้งหมดโดยNSLogไม่คำนึงถึงสิ่งที่อยู่ภายใน
Eric Platon

1
หากเป็นโปรเจ็กต์เก่าที่ไม่มีแฟล็กการดีบักในมาโครพรีโปรเซสเซอร์จะถูกอิมพอร์ตเพื่อเพิ่ม "debug = 1" สำหรับโปรเจ็กต์ไม่ใช่เป้าหมาย
Priebe

1
นอกจากนี้อย่าใช้NSLogเป็นคำสั่งไม่ต้องทำอะไรเช่นif(AllCool) NSLog(@"Cool!Do Nothing!"); else...ใส่NSLogวงเล็บปีกกาแทนif(AllCool) {NSLog(@"Cool!Do Nothing!");} else...
arcady bob

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
คุณวางสิ่งนี้ไว้ที่ไหน?
user6631314

20

นอกจากทุกคนที่แสดงความคิดเห็นอย่างชาญฉลาดว่าการไม่โทรNSLog()เลยในการผลิตจะทำงานได้เร็วขึ้นเล็กน้อยฉันจะเพิ่มว่า:

ทุกNSLog()คนที่ดาวน์โหลดแอปของคุณจากสโตร์และเรียกใช้สตริงเอาต์พุตทั้งหมดจะมองเห็นได้โดยอุปกรณ์ที่เสียบเข้ากับ Mac ที่ใช้ Xcode (ผ่านหน้าต่าง Organizer)

ทั้งนี้ขึ้นอยู่กับข้อมูลที่คุณเข้าสู่ระบบ (และโดยเฉพาะอย่างยิ่งถ้ารายชื่อของแอปเซิร์ฟเวอร์ไม่รับรองความถูกต้อง ฯลฯ ) นี้จะมีปัญหาด้านความปลอดภัยร้ายแรง


ขอบคุณสำหรับข้อมูล - นี่อยู่ในเอกสารที่ไหนหรือเพิ่งค้นพบว่าตัวเอง ยังคงพิมพ์ใน Swift ได้จริงหรือไม่?
Ronny Webers

ฉันจำไม่ได้ว่าอ่านเอกสารใด ๆ ฉันเพิ่งติดตั้งบิลด์ที่เก็บถาวร (ไบนารีเดียวกับที่ฉันส่งไปยังร้านค้า) บนอุปกรณ์ของฉันและเสียบเข้ากับ Xcode ฉันไม่รู้ว่ามันเหมือนกันกับ Swift print()หรือเปล่า แต่ส่วนใหญ่จะเป็นเช่นนั้น
Nicolas Miari

@NicolasMiari คุณหมายถึงอะไรเมื่อเสียบเข้ากับ Xcode? เราจะเสียบไบนารีของเราเข้ากับ Xcode ได้อย่างไรจริงๆแล้วฉันก็อยากลองเหมือนกัน ดังนั้นโปรดแนะนำ. ขอบคุณ
iDevAmit

@iDeveloper ฉันหมายถึงดาวน์โหลดแอปของคุณจาก AppStore ไปยังอุปกรณ์ (เช่น iPhone) เสียบอุปกรณ์นั้นเข้ากับ Xcode ผ่าน USB เปิดแอปของคุณและดูบันทึกในหน้าต่าง "อุปกรณ์" ของ Xcode
Nicolas Miari

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

ใช่คุณควรปิดการใช้งาน โดยเฉพาะอย่างยิ่งถ้าคุณพยายามเพิ่มความเร็วของโค้ดของคุณ NS การบันทึกสิ่งต่างๆทางซ้ายและขวาจะก่อให้เกิดมลพิษในบันทึกของระบบที่นักพัฒนารายอื่นอาจพยายามขุดค้นและอาจส่งผลกระทบอย่างมากต่อโค้ดที่มีความสำคัญต่อความเร็ว (ภายในลูป ฯลฯ ) ฉันเผลอทิ้งข้อความบันทึกบางข้อความไว้ในฟังก์ชันเรียกซ้ำหนึ่งครั้งและ ต้องปล่อยอัปเดต "เพิ่มความเร็ว 30%!" ไม่กี่สัปดาห์ต่อมา ... ;-)


5

คำตอบที่ดีทั้งหมดอย่างไรก็ตามนี่คือเคล็ดลับเล็ก ๆ น้อย ๆ ที่คุณสามารถพิจารณาใช้ได้โดยส่วนใหญ่อยู่ในขั้นตอนการพัฒนา / ทดสอบแอปของคุณ

นอกจากนี้ยังอาจมีประโยชน์สำหรับรหัสรุ่นของแอปหากคุณต้องการเปลี่ยนรหัสดีบักของคุณเท่านั้นไม่ใช่ข้อความที่อาจบ่งชี้ปัญหาที่อยู่นอกเหนือการควบคุมโดยตรงของรหัสของคุณ

เคล็ดลับ:

คุณสามารถปิด NSLog ต่อไฟล์. 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ฟังก์ชัน
Todd Lehman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.