Objective-C/iPhone - 尽可能捕获NSException的信息

9

我正在使用以下代码来捕获应用程序中的异常:

void uncaughtExceptionHandler(NSException *exception) {
    [FlurryAPI logError:@"Uncaught" message:@"Crash!" exception:exception];
}

我想知道是否可以精确定位错误发生的位置,例如UIView、类等。最好能提供尽可能详细的信息,因为这些信息将被FlurryAPI分析。

FlurryAPIhttp://www.flurry.com/

2个回答

16

我最终选择了这个:

void uncaughtExceptionHandler(NSException *exception) {
    NSArray *backtrace = [exception callStackSymbols];
    NSString *platform = [[UIDevice currentDevice] platform];
    NSString *version = [[UIDevice currentDevice] systemVersion];
    NSString *message = [NSString stringWithFormat:@"Device: %@. OS: %@. Backtrace:\n%@",
                         platform,
                         version,
                         backtrace];

    [FlurryAPI logError:@"Uncaught" message:message exception:exception];
}

更新(基于 @TommyG 下面的评论):

AppDelegate-(BOOL)application:didFinishLaunchingWithOptions: 方法末尾添加 NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);。 然后将上述方法添加到 AppDelegate 中。


1
你把这个方法放在哪里?是在应用程序委托中吗?我收到一个警告,说这个方法没有先前的原型。 - TommyG
1
@TommyG 在AppDelegate的- (BOOL)application:didFinishLaunchingWithOptions:方法末尾添加NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);。然后在AppDelegate中添加上述方法。 - alex
1
这个实际上会给你一个堆栈跟踪吗? - jjxtra

3
你可以利用预编译器编写一个宏来收集所有的值,例如:
#define __ThrowException(name, reason, class, function, file, line, info) [NSException exceptionWithName:name reason:[NSString stringWithFormat:@"%s:%i (%@:%s) %@", file, line, class, function, reason]  userInfo:info];
#define ThrowException(name, reason, info) __ThrowException(name, reason, [self class], _cmd, __FILE__, __LINE__, info)

然而,这仅在抛出异常并且在ObjC函数内部时起作用(self和_cmd是您在ObjC函数中获得的第一个参数,其中self是指向类的id,_cmd是可以(当前!)强制转换为const char的选择器)。
但是,如果您只想针对Foundation异常使用此功能,则有两个选项:
1. 将可能引发异常的所有内容包装在@try() @catch()块中,然后抛出新的自定义异常 2. 获取堆栈跟踪,这可能有点困难,因为您的应用程序可能处于不一致状态,并且无法收集所有值。在此处详细介绍了获取当前堆栈跟踪的方法。

我明白了,那么我应该在AppDelegate中定义这些宏吗?如果是的话,我该如何在void uncaughtExceptionHandler(NSException *exception)中使用它们呢? - fulvio
1
@Fulvio Cusumano:啊,好吧,这个宏不应该在你的处理程序中使用,因为此时从预编译器获取所需值已经太晚了,而应该用于创建异常,然后抛出它们。就像我说的,如果你只需要 Foundations 异常,你可以使用 @try() 和 @catch() 来创建新的异常或者沿着堆栈向下走。 - JustSid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接