在主函数中捕获NSException异常

3
我接手的iOS应用程序处理NSExceptions的方式与我之前见到的不同,想知道为什么现在它不起作用了。
在main.m文件中,旧开发人员有以下逻辑:
int main(int argc, char *argv[])
{
    @autoreleasepool {
        int retVal = 0;
        @try {
            retVal =  UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
        @catch (NSException *exception) {
            //
            //Logic to save Exception in DataStore
            //
            NSLog(@"Exception - %@",[exception description]);
            exit(EXIT_FAILURE);
        }
        return retVal;
    }
}

当应用程序再次启动时,您将收到一个提示,询问是否将异常发送给我们,如果您确认,则会将其发送到我们的服务器。
我最近推送了一次针对iOS 7更优化的应用程序更新,注意到我不再收到崩溃应用程序的这些错误报告了。
因此,我通过以下代码进行了测试,我知道它被调用了:
NSArray *array = [NSArray new];

id object = [array objectAtIndex:4];

我收到了这个:
2014-05-12 14:55:57.575 APPNAME[17989:60b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 4 beyond bounds for empty array'
*** First throw call stack:
(0x18ab0b09c 0x196a89d78 0x18aa0c680 0x10007f498 0x18d9e02c0 0x18da997d0 0x18da996cc 0x18da98ba0
 0x18da98840 0x18da98564 0x18da984e4 0x18d9dad78 0x18d5d70cc 0x18d5d1c94 0x18d5d1b4c 
 0x18d5d13d4 0x18d5d1178 0x18d5caa30 0x18aacb7e0 0x18aac8a68 0x18aac8df4 0x18aa09b38 
 0x19042f830 0x18da480e8 0x100036b98 0x197073aa0)
libc++abi.dylib: terminating with uncaught exception of type NSException

如您所见,异常并没有被记录或保存,而是完全未被捕获。
2个问题:
1. 这种做法是否不好?我不认为是,但我只是一名初级开发人员,不太确定是否有更好的方法可以在不使用第三方服务的情况下完成此操作。
2. 您是否了解 iOS 7 中是否有任何更改会影响此(未更改)逻辑?

我的猜测是,现在苹果公司在UIApplicationMain或者UIApplication类的某个地方有一个异常处理程序。 - Brad Allred
2个回答

10

这是不好的实践吗?我不认为是,但我只是一名初级开发人员,也不确定有没有更好的方法在不使用第三方服务的情况下实现这个。

是的,这是不好的实践。 UIApplicationMain() 是一个黑洞;一旦控制权传递到该函数,main() 中除了该调用之外的任何代码都不太可能再次被调用。

它还是一个天真的实现;它记录的标准输出少于正常的异常处理机制(即您看到的输出)。它隐藏了有用于调试的信息,并且很可能会绕过标准的崩溃报告机制。

请注意,还存在全局未经处理的异常处理挂钩。我不建议使用它,但它确实存在。

您知道iOS 7中是否有任何更改会影响此(未更改)逻辑吗?

暂时没有想到,但我还没有查看过。再次说明,UIApplicationMain() 是一个黑洞;它通常不会返回。


我很感激你给出的答案。我明白这是一种不好的做法,因为它依赖于uIApplicationMain。日志记录因素并不是问题,因为我们的异常处理dao和报告类保存了大量数据,并包含我们发送的面包屑。似乎iOS 7可能已经改变了它的返回方式,因为在iOS 7之前,它们都被报告了。 - Rohan Panchal

5

根据异常编程主题,您可以使用NSSetUncaughtExceptionHandler函数来处理未捕获的异常。请尝试以下代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSSetUncaughtExceptionHandler(handleUncaughtException);
    @throw [NSException exceptionWithName:NSGenericException
                                   reason:@"Test uncaught exception handling"
                                 userInfo:nil];

    return YES;
}

void handleUncaughtException(NSException *exception)
{
    NSLog(@"Exception - %@",[exception description]);
    exit(EXIT_FAILURE);
}

我将这个标记为正确答案,因为在我提出这个问题后,我找到了这个确切的答案并且它起作用了。但是我有一个问题,这是否是一个好的做法? - Rohan Panchal
我认为这是一个好的实践,但我想我们应该请@bbum解释为什么他建议不要使用它。 - nalexn

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