iOS应用中的致命错误处理程序

时间:2013-08-08 20:52:10

标签: ios error-handling

当出现严重错误导致我的应用程序无法继续并需要退出时,我想向用户弹出警告框,然后在点按“确定”按钮时关闭应用程序。听起来很简单,对吧?

但是问题在于:我的致命错误处理程序被第三方库调用(我没有他们的源代码)。我给他们一个指向初始化时我的致命错误处理程序的指针,当他们遇到致命错误时,他们只是调用该例程并期望它永远不会返回。如果它返回,第三方库将假设我已经处理了错误并且它将继续运行(可能会破坏数据,因为事情现在处于不一致状态)。我可以在我的错误处理程序结束时退出应用程序(这是他们所期望的),但我希望能够首先向用户显示一条消息,告诉他们问题是什么。

不幸的是,如果我这样做:

-(void)fatalErrorHandler:(NSString *)msg
{
    // Log the error and shut down all the things that need
    // to be shut down before we exit
    // ...

    // Show an alert to the user to tell them what went wrong
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:msg delegate:self cancelButtonTitle:@"Close" otherButtonTitles:nil];
    [alert show];
}


-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    exit(-1);
}

fatalErrorHandler在[alert show]之后返回,它告诉第三方库我已经处理了错误并且它将继续,就像没有发生任何事情一样。这不好。

我不需要从fatalErrorHandler返回。永远。但是因为我在主线程上,所以直到fatalErrorHandler返回时才会出现UIAlertView。捕获22。

关于如何在不从致命错误处理程序返回的情况下向用户显示警报的任何想法?

3 个答案:

答案 0 :(得分:0)

我不知道这是否会奏效,但是如果在它的主体中开始while循环并使用sleep,那么,每个循环1秒钟呢?当Bool变量设置为YES时,可能会从alertViewDelegate退出。

答案 1 :(得分:0)

根据你所写的内容“fatalErrorHandler在[alert show]之后立即返回,它告诉第三方库我已经处理了错误并且它会继续,好像什么都没发生一样。”

我猜你真正需要的是在调用fatalErrorHandler方法时暂停所有内容。要实现此目的,您可以在显示alertView之前停止所有NSTimer,排队方法等。

或者,您可以通过不同的线程显示alertView,然后使用usleep(很长时间)来暂停fatalErrorHandler所在的线程。

答案 2 :(得分:0)

好的,wesley6j的回答给了我一个主意。这就是我想出的:

-(void)fatalErrorHandler:(NSString *)msg
{
    // Pop up an alert to tell the user what went wrong.  Since this error
    // handler could be called from any thread, we have to make sure this happens
    // on the main thread because it does UI stuff
    [self performSelectorOnMainThread:@selector(showMessage:) withObject:msg waitUntilDone:YES];

    // Now, if we're NOT on the main thread, we can just sleep forever and never
    // return from here.  The error handler will exit the app after the user 
    // dismisses the alert box.
    if (![NSThread isMainThread])
        Sleep(0x7fffffff);
    else
    {
        // OTOH, if we ARE on the main thread, we have to get a bit creative.
        // We don't ever want to return from here, because this is a fatal error
        // handler and returning means the caller can continue on its way as if
        // we "handled" the error, which we didn't.  But since we're on the main
        // thread, we can't sleep or exit because then the user will never see 
        // the alert box we popped up in showMessage.  So we loop forever and 
        // keep calling the main run loop directly to let it do its processing
        // and show the alert.  This is what the main run loop does anyway, so
        // in effect, we just become the main run loop.
        for (;;)
        {
            [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: [NSDate date]];
        }
    }
}


-(void)showMessage:(NSString *)msg
{            
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:msg delegate:self cancelButtonTitle:@"Close" otherButtonTitles:nil];
    [alert show];
    [alert release];
}

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    exit(-1);
}

这完美无缺,完全符合我的需要。