iOS - 在main()中捕获异常

时间:2015-01-24 00:52:18

标签: ios exception-handling

所以,我有一个想法捕获 中的意外例外,并尝试清理并优雅地退出:

int main(int argc, char *argv[])
{
    @autoreleasepool
    {
        //return UIApplicationMain(argc, argv, nil, NSStringFromClass([GRWAppDelegate class]));
        @try
        {
            int retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([GRWAppDelegate class]));
            return retVal;
        }
        @catch (NSException *exception)
        {
            [Utilities setPreferencesDefaults];
        }
    }
}

这会捕获异常并更新首选项默认值。

然后我想,为什么退出,只是清理和重新启动,所以我把所有东西都包裹在一个while循环中:

int main(int argc, char *argv[])
{
    while (YES)
    {
        @autoreleasepool
        {
            ...
        }
    }
}

当然,如果真的有效,我就不会在这里。问题是,一旦再次执行

retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([GRWAppDelegate class]));

它会立即引发新的异常:

Assertion failure in void UIApplicationInstantiateSingleton(Class)(), /SourceCache/UIKit/UIKit-2380.17/UIApplication.m:2037

NSInternalInconsistencyException
@"There can only be one UIApplication instance."

有道理,那么有没有办法可以丢弃现有的单身人士并用新的替换它? (虽然我觉得如果可以的话,它并不是真正的单身人士)

目的是,我不希望应用程序崩溃,从而导致糟糕的用户体验。即使他们的状态没有完全恢复,我认为这仍然会比意外退出更好。

我可以尝试处理可能的预期异常,但这是为了尝试捕捉我无法预见的事情。

这应该只能抓住非常特殊的情况,所以如果不能做到这一点并不是那么大,但我想知道如何最好地应对这种情况。

2 个答案:

答案 0 :(得分:6)

这不起作用,因为异常机制在跨堆栈帧抛出时不能正确清理。由于您在main中捕获异常,因此异常已越过多个堆栈帧。

Apple明确指出,的异常可用于不可恢复的编程错误。

请参阅bbum的回答: “任何通过系统框架代码的异常都会使所述框架处于未定义状态。捕获所述异常并尝试从中恢复将导致内存泄漏,未定义的行为和崩溃。”
bbum Also

来自Apple docs

重要提示:您应该保留使用异常进行编程或意外的运行时错误,例如越界收集访问,尝试改变不可变对象,发送无效消息以及丢失与窗口服务器的连接。在创建应用程序时而不是在运行时,通常会使用异常处理这些类型的错误。

答案 1 :(得分:-1)

您可以创建顶级异常处理程序,并在应用程序首次启动时将其设置为默认异常处理程序。最好的地方是AppDelegate的applicationDidFinishLaunching:方法。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSSetUncaughtExceptionHandler(&exceptionHandler);
    // some UI configuration here..
    return YES;
}

void exceptionHandler(NSException *exception)
{
    [Utilities setPreferencesDefaults];

    // You can also write exception message into a log file as well.
    NSLog(@"Stack trace: %@", [exception callStackReturnAddresses]); 
}