Як ви роздруковуєте слід стека на консоль / журнал у какао?


293

Я хотів би записати трасування дзвінків під час певних точок, як, наприклад, невдалі твердження або невиконані виключення.

Відповіді:


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

Цей код працює на будь-якій нитці.


14
Нове в Mac OS X 10.6, якого не існувало, коли це питання було задано спочатку. Для попередньо-снігового леопарда використовуйте функції backtraceта backtrace_symbols; дивіться макетну сторінку (3).
Пітер Хосей

6
Тільки на iOS 4.0 і вище.
Данра

Дякую! Чи є спосіб зробити так, щоб вивести тільки слід стека, скажімо, на 6 рівнів вниз замість усього шляху?
судо

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 ... Apple повинна зробити це стандартом хоча б під час розробки програми. Купа адрес пам’яті ... архаїчна
Russ

Я вкладаю ваші вдосконалення у свою відповідь; Я робив це перед ARC. Дякую.
n13

1
Це працює не у всіх ситуаціях. Це кращий підхід, якщо ви хочете зафіксувати всі незрозумілі винятки: codereview.stackexchange.com/questions/56162/… (Код у цьому питанні трохи складніший, але він також робить більше, ніж просто записувати символи стека викликів.)
nhgrif

Ви можете додати, NSLog(@"[Error] - %@ %@", exception.name, exception.reason);якщо хочете і фактичного винятку
Corentin S.

9

Cocoa вже записує слід стека за невловими винятками з консолі, хоча вони є лише необробленими адресами пам'яті. Якщо ви хочете символічну інформацію в консолі, є якийсь зразок коду від Apple.

Якщо ви хочете генерувати стек стеку у довільній точці коду (і ви перебуваєте на Leopard), перегляньте сторінку "backtrace man". Перед Леопардом ви насправді повинні були перекопати стек викликів.


6
Мабуть, доступні в iOS 4, але не 3.2. Ось що я використав, безсоромно скопіювавши із сторінки "backtrace man": #include <execinfo.h> ... void * callstack [128]; int i, фрейми = backtrace (callstack, 128); char ** strs = backtrace_symbols (callstack, фрейми); for (i = 0; i <кадри; ++ i) {printf ("% s \ n", strs [i]); } безкоштовно (стрс);
mharper

Будучи викликаним в HandleException, він записує зворотній слід самої функції обробника, в той час як [NSException callStackSymbols] показує стек місця, де піднявся виняток. Але якщо ви заміните "backtrace (...)" на: "NSArray arr = [ex callStackReturnAddresses]; int frames = arr.count; for (i = 0; i <кадри; ++ i) callstack [i] = ( void) [((NSNumber *) [arr objectAtIndex: i]) intValue]; " ви отримаєте поточний слід стека винятку. Ось як працює [NSException callStackSymbols], я вважаю: сліди, які вони повертають, рівні і в обох додатках виклики замінюються _mh_execute_header у випуску.
Терцій

6

Це в значній мірі говорить вам, що робити.

По суті, вам потрібно налаштувати обробку виключень додатків для входу в систему, наприклад:

#import <ExceptionHandling/NSExceptionHandler.h>

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

1
Зауважте, хоча це буде працювати лише в зареєстрованому обробнику винятків (не, наприклад, у блоці @catch)
Barry Wark


1

Швидко надрукуйте таким чином:

print("stack trace:\(Thread.callStackSymbols)")
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.