在iPhone顶级异常处理程序中显示警报

在iPhone顶级异常处理程序中显示警报,iphone,objective-c,exception,uialertview,Iphone,Objective C,Exception,Uialertview,我试图在顶级iPhone异常处理程序中显示UIAlertView。处理程序函数如下所示: void applicationExceptionHandler(NSException *ex) { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:[ex reason]

我试图在顶级iPhone异常处理程序中显示UIAlertView。处理程序函数如下所示:

void applicationExceptionHandler(NSException *ex) {
  UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                      message:[ex reason]
                                                      delegate:nil
                                             cancelButtonTitle:@"OK"
                                             otherButtonTitles:nil];
  [alertView show];
}
我在其他地方见过类似的代码(例如)

如果我在调试器中单步执行,我可以看到调用了异常处理程序,并且我可以看到当前屏幕变暗,好像它将在它前面显示警报,但什么也没有出现。在调试器之外,应用程序立即退出并返回系统主屏幕


如果我在ApplicationIDFinishLaunching中捕获错误并在返回之前在那里显示警报,它确实可以工作。我假设警报视图永远不会有机会显示在异常处理程序中,因为应用程序正在终止(而不是坐在那里无所事事,如果我只是退出ApplicationIDFinishLaunching)。有什么方法可以使这项工作正常吗?

您应该验证是否达到了代码要求,或者是否只是显示问题

NSLog将澄清这一点

如果未联系到,您需要防止应用程序关闭,并且您可能需要延迟操作以脱离警报呼叫的上下文:

[self performSelector: @selector(showAlert:) withObject:@"msg" afterDelay: 0.1];
如果您正在访问它,并且执行上下文不是问题,但您只是没有看到警报,那么[alert show]可能不是显示的顶级。在这种情况下,您可能需要通过showinview重定向消息,例如使用操作表:

topDelegate=[[UIApplication sharedApplication] delegate];
topDelegateWindow=[topDelegate.window.subviews objectAtIndex:0];

[actionSheet showInView:topDelegateWindow];

我不清楚
[alertView show]
是如何实现的,但我想它会对视图层次结构进行一些更改,然后将自身设置为在下一次运行循环时显示警报(查找
nsrunlop

但是,由于应用程序即将退出,控件不会返回到运行循环,因此警报永远不会显示。这就是为什么您会看到屏幕变暗(警报级别窗口由
show
立即添加),但警报不会出现(这将发生在运行循环中)

如果在异常处理程序的末尾包含
[[nsrunlop currentlunloop]run]
,则可能会出现警报

如果要让应用程序在警报完成后退出,可以在while循环中调用nsrunlop的
runUntilDate:
,检查标志值以查看警报是否已解除。如果有,只需退出handler函数即可。这意味着您必须在设置该标志的警报上设置一个委托对象


如果你想让你的应用程序继续运行。。。我不太确定。您可以让运行循环继续在异常处理程序中运行,但这可能会产生不良/奇怪的副作用。所以你可能应该让应用退出。此外,如果您确信可以从异常中恢复,那么您应该在某个地方捕获到它。

感谢benzado的帮助,下面是我认为非常棒的通用顶级异常处理程序。我是一个初学者,所以希望它能正确完成,但它确实有效:)

在my…appDelegate.m中:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{        
    [window makeKeyAndVisible];

    NSSetUncaughtExceptionHandler(&exceptionHandler);

    return YES;
}

BOOL exceptionAlertDismissed = FALSE;
void exceptionHandler(NSException *exception)
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"App Committed Suicide"
        message:@"Oh dear, that wasn't supposed to happen. You will have to restart the application... sorry!"
        delegate:[[UIApplication sharedApplication] delegate] cancelButtonTitle:nil otherButtonTitles:@"That's ok!", @"Erm, bye...", nil];
    [alert show];
    [alert release];

    while (exceptionAlertDismissed == FALSE)
    {
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
    }
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    exceptionAlertDismissed = TRUE;
}
在我的…appDelegate.h中:

@interface ...appDelegate : NSObject <UIApplicationDelegate, UIAlertViewDelegate>
...
void exceptionHandler(NSException *exception);
@interface…appDelegate:NSObject
...
无效异常处理程序(NSException*exception);

谢谢,我根据您的回答发布了另一个解决方案。您真的需要向用户显示错误消息吗?如果您能够以静默方式处理异常,并且不必担心如何解决此问题,也许这将是最好的选择。@Nick理想情况下是的,但这是处理未捕获、不可预见、意外异常的代码。希望它永远不会被调用,但如果是,另一种选择是让应用程序在没有警告的情况下突然退出。看起来不错。就我个人而言,我会创建一个单独的对象作为警报的委托。由于我们处于灾难模式,因此与应用程序的其他代码隔离是有意义的。如果与uialertview+blocks实现相结合,则可以很容易地使其变得更漂亮。像这样(不是我的代码):