NSLog ชื่อวิธีการด้วย Objective-C ใน iPhone


153

ขณะนี้เรากำลังกำหนดกลไกการบันทึกเพิ่มเติมเพื่อพิมพ์ชื่อคลาสและหมายเลขบรรทัดซอร์สของบันทึก

#define NCLog(s, ...) NSLog(@"<%@:%d> %@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], \
    __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__])

ตัวอย่างเช่นเมื่อฉันโทร NCLog (@ "Hello world"); ผลลัพธ์จะเป็น:

<ApplicationDelegate:10>Hello world

ตอนนี้ฉันต้องการออกจากระบบชื่อวิธีเช่น:

<ApplicationDelegate:applicationDidFinishLaunching:10>Hello world

ดังนั้นสิ่งนี้จะทำให้การดีบักของเราง่ายขึ้นเมื่อเรารู้วิธีการที่เรียกใช้ ฉันรู้ว่าเรามี Xcode debugger ด้วย แต่บางครั้งฉันก็อยากทำการดีบั๊กด้วยการออกจากระบบ


ในiPhoneโครงการสุดท้ายของฉันฉันทำสิ่งนี้ด้วยตนเอง ชอบที่จะเห็นคำตอบนี้
Jacob Relkin

ซ้ำซ้อนที่เป็นไปได้: stackoverflow.com/questions/969130/…
erkanyildiz

คำตอบ:


261
print(__FUNCTION__) // Swift
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C

Swift 3 ขึ้นไป

print(#function)

120
คุณควรใช้จริงๆNSLog(@"%@", NSStringFromSelector(_cmd))ถ้าคุณจะใช้_cmdเนื่องจาก AFAIK Apple ประกาศว่า_cmdเป็นประเภทSELไม่ใช่ C-string เพียงเพราะมันถูกนำมาใช้ในรูปแบบ C-string (ซึ่งเป็นเวอร์ชั่นปัจจุบันของ Mac OS X และ iPhone OS) ไม่ได้หมายความว่าคุณควรใช้มันในแบบนั้นเนื่องจาก Apple สามารถเปลี่ยนแปลงได้ในการอัปเดตระบบปฏิบัติการ
Nick Forge

5
ใช่ NSStringFromSelector เป็นคำตอบที่ถูกต้องมากขึ้น ฉันไม่เคยใช้ _cmd เป็นสตริง c สำหรับสิ่งใดนอกจากรหัสดีบัก
drawnonward

ว้าวคอมไพเลอร์ร้องทุกข์เกี่ยวกับความเข้ากันไม่ได้ของตัวชี้ แต่มันใช้งานได้ ... ดังนั้น _cmd (ประเภท: SEL) เป็น char *!
Nicolas Miari

3
วิธีการเรียกร้องเช่นได้รับการแปลงเป็นสายฟังก์ชัน[self doSomething:arg1 somethingElse:arg2] C objc_msgSend(self, "doSomething:somethingElse:, arg1, arg2);พารามิเตอร์ที่สองของการยิงobjc_msgSend() char*โปรดจำไว้ว่าเนื่องจาก Objective-C รันไทม์เป็นแบบไดนามิกจริง ๆ แล้วมันใช้ตารางการค้นหาเพื่อหาวิธีที่คลาสที่จะเรียกใช้เพื่อให้ char * สะดวกเนื่องจากวิธีการแสดงเป็นสตริงในตารางการค้นหา
Jack Lawrence

1
สำหรับ Swift 2.2 ควรใช้print("\(#function)")
Jake Lin

161

ในการตอบคำถามของคุณทางเทคนิคคุณต้องการ:

NSLog(@"<%@:%@:%d>", NSStringFromClass([self class]), NSStringFromSelector(_cmd), __LINE__);

หรือคุณสามารถทำ:

NSLog(@"%s", __PRETTY_FUNCTION__);

2
ด้วย__FUNCTION__และมันก็สวยเทียบเท่ายังมีอยู่ในฟังก์ชั่น C
Georg Fritzsche

NB __FUNCTION__ยังรวมถึงชื่อคลาส
OrangeDog

1
มีความแตกต่างในการใช้ NSLog (@ "% s", _func_ ) หรือไม่ OR NSLog (@ "% s", _PRETTY_FUNCTION_ ) ???
Ravi

83

TL; DR

NSLog( @"ERROR %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

รายละเอียด

Apple มีหน้าถาม & ตอบทางเทคนิค: QA1669 - ฉันจะเพิ่มข้อมูลบริบท - เช่นวิธีปัจจุบันหรือหมายเลขบรรทัด - ลงในคำชี้แจงการบันทึกของฉันได้อย่างไร

เพื่อช่วยในการบันทึก:

  • ตัวประมวลผลล่วงหน้า C จัดเตรียมมาโครสองสามตัว
  • Objective-C ให้การแสดงออก (วิธีการ)
    • ผ่านอาร์กิวเมนต์โดยนัยสำหรับตัวเลือกของวิธีการปัจจุบัน:_cmd

ตามคำตอบอื่น ๆ ที่ระบุไว้เพื่อรับชื่อวิธีปัจจุบันเพียงโทร:

NSStringFromSelector(_cmd)

ในการรับชื่อวิธีการปัจจุบันและหมายเลขบรรทัดปัจจุบันให้ใช้มาโครสองตัวนี้__func__และ__LINE__ตามที่เห็นที่นี่:

NSLog(@"%s:%d someObject=%@", __func__, __LINE__, someObject);

อีกตัวอย่างหนึ่ง…ตัวอย่างโค้ดที่ฉันเก็บไว้ในรหัสตัวอย่างโค้ดของ Xcode:

NSLog( @"ERROR %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

…และ TRACE แทนที่จะเป็น ERROR …

NSLog( @"TRACE %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

…และอีกอันที่ยาวกว่าโดยใช้คำอธิบายแบบนุ่มนวลผ่านค่า ( [rows count]) ...

NSLog( @"TRACE %@ METHOD %s:%d.", [NSString stringWithFormat:@"'Table of Contents.txt' file's count of Linefeed-delimited rows: %u.", [rows count]] , __func__, __LINE__ );

มาโครตัวประมวลผลล่วงหน้าสำหรับการบันทึก

สังเกตการใช้อักขระขีดล่างคู่รอบทั้งสองด้านของแมโคร

| มาโคร | รูปแบบ | ลักษณะ
  __func__% s ลายเซ็นฟังก์ชั่นปัจจุบัน
  __LINE__% d หมายเลขบรรทัดปัจจุบัน
  __FILE__% s พา ธ เต็มไปยังไฟล์ต้นฉบับ
  __PRETTY_FUNCTION__% s ไลค์ __func__ แต่รวมถึง verbose
                                    พิมพ์ข้อมูลในรหัส C ++ 

นิพจน์สำหรับการบันทึก

| นิพจน์ | รูปแบบ | ลักษณะ
  NSStringFromSelector (_cmd)% @ ชื่อของตัวเลือกปัจจุบัน
  NSStringFromClass ([ระดับตนเอง])% @ ชื่อคลาสของวัตถุปัจจุบัน
  [[NSString% @ ชื่อไฟล์รหัสต้นฉบับ
    stringWithUTF8String: __ FILE__]   
    lastPathComponent] 
  [NSThread callStackSymbols]% @ NSArray ของการติดตามสแต็ก

กรอบการบันทึก

เฟรมเวิร์กการบันทึกบางอย่างอาจช่วยในการรับเมธอดหรือหมายเลขบรรทัดปัจจุบันเช่นกัน ฉันไม่แน่ใจเพราะฉันใช้กรอบการบันทึกที่ยอดเยี่ยมใน Java ( SLF4J + LogBack ) แต่ไม่ใช่ Cocoa

ดูคำถามนี้สำหรับลิงก์ไปยังกรอบการทำโกโก้ที่หลากหลาย

ชื่อของตัวเลือก

หากคุณมีตัวแปร Selector ( SEL ) คุณสามารถพิมพ์ชื่อเมธอด ("ข้อความ") ได้สองวิธีดังที่อธิบายไว้โดยโพสต์บล็อกCodec นี้:

  • ใช้การโทร Objective-C ไปที่NSStringFromSelector :
    NSLog(@"%@", NSStringFromSelector(selector) );
  • ใช้ straight C:
    NSLog(@"%s", selector );

ข้อมูลนี้ดึงมาจากหน้าเอกสาร Apple ที่เชื่อมโยงตั้งแต่ 2013-07-19 หน้านั้นได้รับการปรับปรุงล่าสุดเมื่อวันที่ 2011-10-04


1
สำหรับ C ให้ใช้sel_getName(SEL)เนื่องจาก SEL เป็นชนิดทึบแสงและอาจไม่ใช่char *
Ethan Reesor

8
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C
print(__FUNCTION__) // Swift

4
สำหรับทุกคนที่เจอคำตอบนี้ในอนาคต: มันเทียบเท่ากับคำตอบที่ยอมรับ แต่คำตอบที่ได้รับการยอมรับนั้นแตกต่างกันเมื่อมีการโพสต์คำตอบนี้ (คำตอบที่ยอมรับได้ถูกแก้ไขในปี 2014) ฉันกำลังจะลงคะแนน แต่หลังจากการสอบสวนเล็กน้อยลงคะแนนแทน :)
FreeNickname

0

จริงๆแล้วมันง่ายเหมือน:

printf(_cmd);

ด้วยเหตุผลบางอย่างทำให้ iOS อนุญาตให้ _cmd ส่งผ่านเป็น char ที่แท้จริงโดยไม่มีแม้แต่คำเตือนการคอมไพล์ ใครจะรู้


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.