คุณจะพิมพ์การติดตามสแต็กไปยังคอนโซล / บันทึกใน Cocoa ได้อย่างไร


293

ฉันต้องการบันทึกการติดตามการโทรในบางจุดเช่นการยืนยันที่ล้มเหลวหรือข้อยกเว้นที่ไม่ได้ตรวจสอบ

คำตอบ:


544
 NSLog(@"%@",[NSThread callStackSymbols]);

รหัสนี้ใช้ได้กับทุกเธรด


14
ใหม่ใน Mac OS X 10.6 ซึ่งไม่มีอยู่เมื่อมีการถามคำถามนี้ สำหรับ pre-Snow-Leopard ให้ใช้backtraceและbacktrace_symbolsฟังก์ชั่น ดู mantrace (3) manpage
Peter Hosey

6
เฉพาะใน iOS 4.0 ขึ้นไป
Danra

ขอบคุณ! มีวิธีที่จะทำสิ่งนี้เพียงพิมพ์ stack trace, พูด, 6 ระดับลงแทนทั้งหมดหรือไม่
sudo

9000, ใช้backtrace/backtrace_symbolsโดยตรง
dymv

34

คำตอบของ n13 ไม่ได้ผล - ฉันปรับเปลี่ยนเล็กน้อยเพื่อให้ได้สิ่งนี้

#import <UIKit/UIKit.h>

#import "AppDelegate.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        int retval;
        @try{
            retval = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
        @catch (NSException *exception)
        {
            NSLog(@"Gosh!!! %@", [exception callStackSymbols]);
            @throw;
        }
        return retval;
    }
}

4
Gah ... แอปเปิ้ลควรทำให้เป็นมาตรฐานอย่างน้อยขณะที่พัฒนาแอปพลิเคชัน ที่อยู่หน่วยความจำจำนวนมากคือ ... archaic
Russ

ฉันใส่การปรับปรุงของคุณในคำตอบของฉัน; ฉันทำสิ่งนี้ก่อน ARC ขอบคุณ
n13

1
นี้ไม่ได้ทำงานในทุกสถานการณ์ นี่เป็นวิธีที่ดีกว่าถ้าคุณต้องการที่จะตรวจจับข้อยกเว้นที่ไม่ได้ตรวจสอบทั้งหมด: codereview.stackexchange.com/questions/56162/… (รหัสในคำถามนั้นค่อนข้างซับซ้อนเล็กน้อย แต่ก็ทำได้มากกว่าการบันทึกสัญลักษณ์สแต็กการโทร)
nhgrif

คุณสามารถเพิ่มได้NSLog(@"[Error] - %@ %@", exception.name, exception.reason);หากคุณต้องการข้อยกเว้นที่แท้จริงเช่นกัน
Corentin S.

9

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

หากคุณต้องการสร้างการติดตามสแต็คที่จุดตามอำเภอใจในรหัสของคุณ (และคุณอยู่ใน Leopard) ดูหน้าคนย้อนหลัง ก่อน Leopard คุณต้องขุดผ่าน call stack เอง


6
เห็นได้ชัดว่ามีใน iOS 4 แต่ไม่ใช่ 3.2 นี่คือสิ่งที่ฉันใช้คัดลอกจากหน้าคนหน้าด้านหลัง: #include <execinfo.h> ... void * callstack [128]; int i, frames = backtrace (callstack, 128); ถ่าน ** strs = backtrace_symbols (callstack เฟรม); สำหรับ (i = 0; i <frames; ++ i) {printf ("% s \ n", strs [i]); } ฟรี (strs);
mharper

การเรียกใช้ใน HandleException จะเขียนการติดตามกลับของฟังก์ชันตัวจัดการเองในขณะที่ [NSException callStackSymbols] แสดงสแต็กของสถานที่ที่มีข้อยกเว้นยก แต่ถ้าคุณแทนที่ "backtrace (... )" ด้วย: "NSArray arr = [ex callStackReturnAddresses]; int frames = arr.count; สำหรับ (i = 0; i <frames; ++ i) callstack [i] = ( เป็นโมฆะ) [((NSNumber *) [arr objectAtIndex: i]) intValue]; " คุณจะได้รับการติดตามสแต็กข้อยกเว้นปัจจุบัน นี่คือวิธีที่ [NSException callStackSymbols] ทำงานฉันคิดว่า: ร่องรอยที่พวกเขากลับมามีค่าเท่ากันและในการโทรทั้งสองแอปจะถูกแทนที่ด้วย _mh_execute_header ในการเปิดตัว
Tertium

6

นี้สวยมากจะบอกคุณว่าจะทำอย่างไร

โดยพื้นฐานแล้วคุณจำเป็นต้องตั้งค่าการจัดการข้อยกเว้นแอปพลิเคชันเพื่อเข้าสู่ระบบสิ่งที่ชอบ:

#import <ExceptionHandling/NSExceptionHandler.h>

[[NSExceptionHandler defaultExceptionHandler] 
                  setExceptionHandlingMask: NSLogUncaughtExceptionMask | 
                                            NSLogUncaughtSystemExceptionMask | 
                                            NSLogUncaughtRuntimeErrorMask]

1
โปรดทราบว่าสิ่งนี้จะใช้ได้ภายในตัวจัดการข้อยกเว้นที่ลงทะเบียนแล้วเท่านั้น (ไม่เช่นในบล็อก @catch)
Barry Wark

2

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


วิธีใช้งาน Swift
Pedro Paulo Amorim

1

ในการพิมพ์อย่างรวดเร็วด้วยวิธีนี้:

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